@takuhon/core 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -3103,6 +3103,61 @@ declare function exportTakuhon(data: Takuhon, options?: ExportOptions): Exported
3103
3103
  */
3104
3104
  declare function importTakuhon(data: ExportedTakuhon): Takuhon;
3105
3105
 
3106
+ /**
3107
+ * Public-endpoint privacy filter for takuhon profile documents.
3108
+ *
3109
+ * Strips fields that the spec's privacy posture marks as opt-in for public
3110
+ * exposure, before the document reaches a public reader (a public API
3111
+ * response, a statically built page, …). The filter is deliberately
3112
+ * conservative: when `meta.privacy` is absent the most restrictive
3113
+ * interpretation applies (everything sensitive is hidden), and the operator
3114
+ * must explicitly opt into disclosure by setting the relevant flag to
3115
+ * `false`.
3116
+ *
3117
+ * This lives in `@takuhon/core` because it is a pure transform over the core
3118
+ * document types with no transport coupling, so every public surface — the
3119
+ * API layer, the CLI's `build`, future renderers — applies the exact same
3120
+ * projection. `@takuhon/api` re-exports it for backwards compatibility.
3121
+ *
3122
+ * Fields filtered:
3123
+ *
3124
+ * - `certifications[*].credentialId` — hidden when
3125
+ * `meta.privacy.hideCredentialIds !== false` (default true).
3126
+ * - `education[*].grade` — hidden when
3127
+ * `meta.privacy.hideEducationGrades !== false` (default true).
3128
+ * - `contact.email` — hidden when `contact.showEmail !== true`.
3129
+ *
3130
+ * `patents[*].patentNumber` is **not** filtered. Patent numbers are public
3131
+ * records (issued patents are published by the granting office) and Spec
3132
+ * §6.21 explicitly excludes them from the privacy block.
3133
+ *
3134
+ * Behavior:
3135
+ *
3136
+ * - Pure function. The input is never mutated; a shallow-copied result is
3137
+ * returned with only the touched arrays / objects replaced.
3138
+ * - When no filter applies (every flag opts into disclosure), the original
3139
+ * reference is returned as-is so callers can compare by identity.
3140
+ * - Admin endpoints (`/api/admin/*`, including `/api/admin/export`) MUST NOT
3141
+ * call this helper — they always serve the full document to authenticated
3142
+ * callers.
3143
+ */
3144
+
3145
+ /**
3146
+ * Union of the two profile shapes that traverse the public path. The fields
3147
+ * the filter touches (`certifications[*].credentialId`, `education[*].grade`,
3148
+ * `contact.email`) are structurally identical between {@link Takuhon} and
3149
+ * {@link LocalizedTakuhon}, so the same logic applies to either shape.
3150
+ */
3151
+ type FilterableProfile = Takuhon | LocalizedTakuhon;
3152
+ /**
3153
+ * Return a privacy-filtered copy of `profile` suitable for public responses.
3154
+ *
3155
+ * @param profile Either a raw {@link Takuhon} or a locale-resolved
3156
+ * {@link LocalizedTakuhon}. The output preserves the input's
3157
+ * exact shape.
3158
+ */
3159
+ declare function applyPublicPrivacyFilter<T extends FilterableProfile>(profile: T): T;
3160
+
3106
3161
  /**
3107
3162
  * Forward migration entry point for takuhon documents.
3108
3163
  *
@@ -3355,4 +3410,4 @@ declare class ConflictError extends StorageError {
3355
3410
  */
3356
3411
  declare const SCHEMA_VERSION = "0.4.0";
3357
3412
 
3358
- export { type Address, type AssetOptions, type AssetRecord, type Avatar, type Career, type Certification, ConflictError, type Contact, type ContentLicense, type ContentLicenseAttribution, type Course, type Education, type ExportOptions, type ExportedTakuhon, type Honor, ImportError, type Iso3166Alpha2, type IsoDateTime, type Language, type LanguageProficiency, type Link, type LinkBuiltin, type LinkCustom, type LinkType, type LocaleTag, type LocalizedAddress, type LocalizedAvatar, type LocalizedBody, type LocalizedCareer, type LocalizedCertification, type LocalizedCourse, type LocalizedEducation, type LocalizedHonor, type LocalizedLanguage, type LocalizedLink, type LocalizedLinkBuiltin, type LocalizedLinkCustom, type LocalizedMembership, type LocalizedPatent, type LocalizedProfile, type LocalizedProject, type LocalizedPublication, type LocalizedRecommendation, type LocalizedRecommendationAuthor, type LocalizedTakuhon, type LocalizedTestScore, type LocalizedTitle, type LocalizedVolunteering, type Membership, type Meta, type MetaPrivacy, type Migration, MigrationError, type NormalizedTakuhon, NotFoundError, type Patent, type PatentStatus, type Profile, type Project, type Publication, type Recommendation, type RecommendationAuthor, SCHEMA_VERSION, SUPPORTED_SCHEMA_VERSIONS, type Schema, type Settings, type Skill, type Slug, StorageError, type Takuhon, type TakuhonAssetStorage, type TakuhonStorage, type TestScore, type ValidationError, type ValidationResult, type Volunteering, type YearMonth, exportTakuhon, generateJsonLd, generatePersonJsonLd, generateProfilePageJsonLd, importTakuhon, migrateTakuhon, migrations, normalize, resolveLocale, schema, validate };
3413
+ export { type Address, type AssetOptions, type AssetRecord, type Avatar, type Career, type Certification, ConflictError, type Contact, type ContentLicense, type ContentLicenseAttribution, type Course, type Education, type ExportOptions, type ExportedTakuhon, type Honor, ImportError, type Iso3166Alpha2, type IsoDateTime, type Language, type LanguageProficiency, type Link, type LinkBuiltin, type LinkCustom, type LinkType, type LocaleTag, type LocalizedAddress, type LocalizedAvatar, type LocalizedBody, type LocalizedCareer, type LocalizedCertification, type LocalizedCourse, type LocalizedEducation, type LocalizedHonor, type LocalizedLanguage, type LocalizedLink, type LocalizedLinkBuiltin, type LocalizedLinkCustom, type LocalizedMembership, type LocalizedPatent, type LocalizedProfile, type LocalizedProject, type LocalizedPublication, type LocalizedRecommendation, type LocalizedRecommendationAuthor, type LocalizedTakuhon, type LocalizedTestScore, type LocalizedTitle, type LocalizedVolunteering, type Membership, type Meta, type MetaPrivacy, type Migration, MigrationError, type NormalizedTakuhon, NotFoundError, type Patent, type PatentStatus, type Profile, type Project, type Publication, type Recommendation, type RecommendationAuthor, SCHEMA_VERSION, SUPPORTED_SCHEMA_VERSIONS, type Schema, type Settings, type Skill, type Slug, StorageError, type Takuhon, type TakuhonAssetStorage, type TakuhonStorage, type TestScore, type ValidationError, type ValidationResult, type Volunteering, type YearMonth, applyPublicPrivacyFilter, exportTakuhon, generateJsonLd, generatePersonJsonLd, generateProfilePageJsonLd, importTakuhon, migrateTakuhon, migrations, normalize, resolveLocale, schema, validate };
package/dist/index.js CHANGED
@@ -1667,6 +1667,47 @@ function importTakuhon(data) {
1667
1667
  return JSON.parse(JSON.stringify(result.data));
1668
1668
  }
1669
1669
 
1670
+ // src/privacy-filter.ts
1671
+ function applyPublicPrivacyFilter(profile) {
1672
+ const hideCredentialIds = profile.meta.privacy?.hideCredentialIds !== false;
1673
+ const hideEducationGrades = profile.meta.privacy?.hideEducationGrades !== false;
1674
+ const allowEmail = profile.contact.showEmail === true;
1675
+ const stripCertifications = hideCredentialIds && hasAnyCredentialId(profile);
1676
+ const stripEducation = hideEducationGrades && hasAnyGrade(profile);
1677
+ const stripEmail = !allowEmail && profile.contact.email !== void 0;
1678
+ if (!stripCertifications && !stripEducation && !stripEmail) {
1679
+ return profile;
1680
+ }
1681
+ const out = { ...profile };
1682
+ if (stripCertifications) {
1683
+ out.certifications = profile.certifications.map(stripCredentialId);
1684
+ }
1685
+ if (stripEducation) {
1686
+ out.education = profile.education.map(stripGrade);
1687
+ }
1688
+ if (stripEmail) {
1689
+ const { email: _omit, ...rest } = profile.contact;
1690
+ out.contact = rest;
1691
+ }
1692
+ return out;
1693
+ }
1694
+ function hasAnyCredentialId(profile) {
1695
+ return profile.certifications.some((c) => c.credentialId !== void 0);
1696
+ }
1697
+ function hasAnyGrade(profile) {
1698
+ return profile.education.some((e) => e.grade !== void 0);
1699
+ }
1700
+ function stripCredentialId(item) {
1701
+ if (item.credentialId === void 0) return item;
1702
+ const { credentialId: _omit, ...rest } = item;
1703
+ return rest;
1704
+ }
1705
+ function stripGrade(item) {
1706
+ if (item.grade === void 0) return item;
1707
+ const { grade: _omit, ...rest } = item;
1708
+ return rest;
1709
+ }
1710
+
1670
1711
  // src/migrations/_chain.ts
1671
1712
  function findMigrationChain(from, to, registry) {
1672
1713
  if (from === to) return [];
@@ -1798,6 +1839,7 @@ export {
1798
1839
  SCHEMA_VERSION,
1799
1840
  SUPPORTED_SCHEMA_VERSIONS,
1800
1841
  StorageError,
1842
+ applyPublicPrivacyFilter,
1801
1843
  exportTakuhon,
1802
1844
  generateJsonLd,
1803
1845
  generatePersonJsonLd,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../takuhon.schema.json","../src/schema.ts","../src/validate.ts","../src/normalize.ts","../src/locale-tag.ts","../src/resolve-locale.ts","../src/jsonld.ts","../src/export.ts","../src/migrations/_chain.ts","../src/migrations/v0.1.0-to-v0.2.0.ts","../src/migrations/v0.2.0-to-v0.3.0.ts","../src/migrations/v0.3.0-to-v0.4.0.ts","../src/migrations/index.ts","../src/migrate.ts","../src/storage-interface.ts","../src/index.ts"],"sourcesContent":["{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://takuhon.example/schemas/0.4.0/takuhon.schema.json\",\n \"title\": \"Takuhon Profile\",\n \"description\": \"Portable profile data format consumed by @takuhon/core. The canonical contract for profile content authored as takuhon.json.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"schemaVersion\",\n \"profile\",\n \"links\",\n \"careers\",\n \"projects\",\n \"skills\",\n \"contact\",\n \"settings\",\n \"meta\"\n ],\n \"properties\": {\n \"schemaVersion\": {\n \"type\": \"string\",\n \"pattern\": \"^[0-9]+\\\\.[0-9]+\\\\.[0-9]+(-[a-zA-Z0-9.-]+)?$\",\n \"description\": \"Semantic version of the takuhon schema this document conforms to.\"\n },\n \"profile\": { \"$ref\": \"#/$defs/Profile\" },\n \"links\": {\n \"type\": \"array\",\n \"maxItems\": 100,\n \"items\": { \"$ref\": \"#/$defs/Link\" }\n },\n \"careers\": {\n \"type\": \"array\",\n \"maxItems\": 50,\n \"items\": { \"$ref\": \"#/$defs/Career\" }\n },\n \"projects\": {\n \"type\": \"array\",\n \"maxItems\": 100,\n \"items\": { \"$ref\": \"#/$defs/Project\" }\n },\n \"skills\": {\n \"type\": \"array\",\n \"maxItems\": 200,\n \"items\": { \"$ref\": \"#/$defs/Skill\" }\n },\n \"certifications\": {\n \"type\": \"array\",\n \"maxItems\": 50,\n \"items\": { \"$ref\": \"#/$defs/Certification\" }\n },\n \"memberships\": {\n \"type\": \"array\",\n \"maxItems\": 50,\n \"items\": { \"$ref\": \"#/$defs/Membership\" }\n },\n \"volunteering\": {\n \"type\": \"array\",\n \"maxItems\": 50,\n \"items\": { \"$ref\": \"#/$defs/Volunteering\" }\n },\n \"honors\": {\n \"type\": \"array\",\n \"maxItems\": 50,\n \"items\": { \"$ref\": \"#/$defs/Honor\" }\n },\n \"education\": {\n \"type\": \"array\",\n \"maxItems\": 30,\n \"items\": { \"$ref\": \"#/$defs/Education\" }\n },\n \"publications\": {\n \"type\": \"array\",\n \"maxItems\": 100,\n \"items\": { \"$ref\": \"#/$defs/Publication\" }\n },\n \"languages\": {\n \"type\": \"array\",\n \"maxItems\": 30,\n \"items\": { \"$ref\": \"#/$defs/Language\" }\n },\n \"courses\": {\n \"type\": \"array\",\n \"maxItems\": 100,\n \"items\": { \"$ref\": \"#/$defs/Course\" }\n },\n \"patents\": {\n \"type\": \"array\",\n \"maxItems\": 50,\n \"items\": { \"$ref\": \"#/$defs/Patent\" }\n },\n \"testScores\": {\n \"type\": \"array\",\n \"maxItems\": 30,\n \"items\": { \"$ref\": \"#/$defs/TestScore\" }\n },\n \"recommendations\": {\n \"type\": \"array\",\n \"maxItems\": 50,\n \"items\": { \"$ref\": \"#/$defs/Recommendation\" }\n },\n \"contact\": { \"$ref\": \"#/$defs/Contact\" },\n \"settings\": { \"$ref\": \"#/$defs/Settings\" },\n \"meta\": { \"$ref\": \"#/$defs/Meta\" }\n },\n \"$defs\": {\n \"LocaleTag\": {\n \"type\": \"string\",\n \"minLength\": 2,\n \"maxLength\": 35,\n \"pattern\": \"^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})*$\",\n \"description\": \"BCP-47 language tag (e.g., 'en', 'ja', 'zh-Hant', 'pt-BR').\"\n },\n \"Iso3166Alpha2\": {\n \"type\": \"string\",\n \"pattern\": \"^[A-Z]{2}$\",\n \"description\": \"ISO 3166-1 alpha-2 country code (uppercase, two letters).\"\n },\n \"YearMonth\": {\n \"type\": \"string\",\n \"pattern\": \"^[0-9]{4}-(0[1-9]|1[0-2])$\",\n \"description\": \"Year-month in 'YYYY-MM' format (Gregorian calendar).\"\n },\n \"IsoDateTime\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"ISO 8601 date-time (e.g., 2026-05-11T12:34:56Z).\"\n },\n \"Url\": {\n \"type\": \"string\",\n \"format\": \"uri\",\n \"maxLength\": 2048\n },\n \"Email\": {\n \"type\": \"string\",\n \"format\": \"email\",\n \"maxLength\": 254\n },\n \"Slug\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 64,\n \"pattern\": \"^[a-z0-9][a-z0-9-]*$\",\n \"description\": \"URL-safe identifier (lowercase alphanumerics and hyphens, must start with alphanumeric).\"\n },\n \"LocalizedTitle\": {\n \"type\": \"object\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"type\": \"string\",\n \"pattern\": \"^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})*$\"\n },\n \"additionalProperties\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 200\n },\n \"description\": \"Map of BCP-47 locale tag to short title-like string (max 200 chars per value).\"\n },\n \"LocalizedBody\": {\n \"type\": \"object\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"type\": \"string\",\n \"pattern\": \"^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})*$\"\n },\n \"additionalProperties\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 5000\n },\n \"description\": \"Map of BCP-47 locale tag to body-length string (max 5000 chars per value).\"\n },\n \"LinkType\": {\n \"type\": \"string\",\n \"enum\": [\n \"website\",\n \"blog\",\n \"github\",\n \"gitlab\",\n \"linkedin\",\n \"x\",\n \"mastodon\",\n \"bluesky\",\n \"instagram\",\n \"youtube\",\n \"threads\",\n \"facebook\",\n \"email\",\n \"rss\",\n \"custom\"\n ],\n \"description\": \"Identifies the kind of link. 'custom' requires iconUrl.\"\n },\n \"Profile\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"displayName\"],\n \"properties\": {\n \"displayName\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"tagline\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"bio\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"avatar\": { \"$ref\": \"#/$defs/Avatar\" },\n \"location\": { \"$ref\": \"#/$defs/Address\" }\n }\n },\n \"Avatar\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"url\"],\n \"properties\": {\n \"url\": {\n \"type\": \"string\",\n \"format\": \"uri-reference\",\n \"maxLength\": 2048,\n \"description\": \"URL or path to the avatar image.\"\n },\n \"alt\": { \"$ref\": \"#/$defs/LocalizedTitle\" }\n }\n },\n \"Address\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"properties\": {\n \"country\": { \"$ref\": \"#/$defs/Iso3166Alpha2\" },\n \"region\": { \"type\": \"string\", \"maxLength\": 100 },\n \"locality\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"display\": { \"$ref\": \"#/$defs/LocalizedTitle\" }\n }\n },\n \"Link\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"id\", \"type\", \"url\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"type\": { \"$ref\": \"#/$defs/LinkType\" },\n \"label\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"featured\": { \"type\": \"boolean\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 },\n \"iconUrl\": { \"$ref\": \"#/$defs/Url\" }\n },\n \"allOf\": [\n {\n \"if\": {\n \"properties\": { \"type\": { \"const\": \"custom\" } },\n \"required\": [\"type\"]\n },\n \"then\": {\n \"properties\": { \"iconUrl\": { \"$ref\": \"#/$defs/Url\" } },\n \"required\": [\"iconUrl\"]\n }\n }\n ]\n },\n \"Career\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"organization\", \"role\", \"startDate\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"organization\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"role\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"startDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"endDate\": {\n \"anyOf\": [{ \"$ref\": \"#/$defs/YearMonth\" }, { \"type\": \"null\" }]\n },\n \"isCurrent\": { \"type\": \"boolean\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"location\": { \"$ref\": \"#/$defs/Address\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Project\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"title\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"title\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"tags\": {\n \"type\": \"array\",\n \"maxItems\": 30,\n \"items\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 50 }\n },\n \"relatedCareerId\": { \"$ref\": \"#/$defs/Slug\" },\n \"startDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"endDate\": {\n \"anyOf\": [{ \"$ref\": \"#/$defs/YearMonth\" }, { \"type\": \"null\" }]\n },\n \"highlighted\": { \"type\": \"boolean\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Skill\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"label\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"label\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 100 },\n \"category\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 64,\n \"description\": \"Recommended values (extensible): programming, design, business, communication, language, music, art, sports, other.\"\n },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Contact\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"properties\": {\n \"email\": { \"$ref\": \"#/$defs/Email\" },\n \"showEmail\": { \"type\": \"boolean\", \"default\": false },\n \"formUrl\": { \"$ref\": \"#/$defs/Url\" }\n }\n },\n \"Settings\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"defaultLocale\", \"availableLocales\"],\n \"properties\": {\n \"defaultLocale\": { \"$ref\": \"#/$defs/LocaleTag\" },\n \"fallbackLocale\": { \"$ref\": \"#/$defs/LocaleTag\" },\n \"availableLocales\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"maxItems\": 50,\n \"uniqueItems\": true,\n \"items\": { \"$ref\": \"#/$defs/LocaleTag\" }\n },\n \"theme\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 64,\n \"description\": \"UI theme identifier. 'default' is the built-in theme; adapters may add more.\"\n },\n \"showPoweredBy\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"Display the 'Powered by takuhon' attribution in the rendered profile.\"\n },\n \"enableJsonLd\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"Emit Schema.org JSON-LD on the rendered profile page.\"\n },\n \"enableApi\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"Expose the public read API endpoints (GET /api/profile, /api/jsonld, /api/schema, /takuhon.json).\"\n },\n \"enableAnalytics\": {\n \"type\": \"boolean\",\n \"default\": false,\n \"description\": \"Opt-in flag for first-party analytics. Default is false to keep takuhon privacy-respecting by default.\"\n }\n }\n },\n \"Meta\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"contentLicense\"],\n \"properties\": {\n \"createdAt\": { \"$ref\": \"#/$defs/IsoDateTime\" },\n \"updatedAt\": { \"$ref\": \"#/$defs/IsoDateTime\" },\n \"generator\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 100,\n \"description\": \"Tool that produced this document (e.g. 'Takuhon', 'create-takuhon@0.1.0').\"\n },\n \"contentLicense\": { \"$ref\": \"#/$defs/ContentLicense\" },\n \"privacy\": { \"$ref\": \"#/$defs/MetaPrivacy\" }\n }\n },\n \"ContentLicense\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"spdxId\"],\n \"properties\": {\n \"spdxId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 64,\n \"description\": \"SPDX identifier (e.g., 'CC-BY-4.0', 'CC0-1.0') or 'Proprietary'. No default; the profile owner must choose explicitly.\"\n },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"attribution\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"name\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 200 },\n \"url\": { \"$ref\": \"#/$defs/Url\" }\n }\n },\n \"rights\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 1000,\n \"description\": \"Free-form rights statement (used when spdxId='Proprietary' or for additional notices).\"\n }\n }\n },\n \"MetaPrivacy\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"description\": \"Opt-out flags that strip personally identifying fields from public API output (GET /api/profile, /api/jsonld, /takuhon.json). Admin endpoints (PUT /api/admin/*, GET /api/admin/export) ignore these flags. Privacy-by-default: omitting the object or individual flags is equivalent to true.\",\n \"properties\": {\n \"hideCredentialIds\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"When true (default), strip certifications[*].credentialId from public responses.\"\n },\n \"hideEducationGrades\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"When true (default), strip education[*].grade from public responses.\"\n }\n }\n },\n \"Certification\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"title\", \"issuingOrganization\", \"issueDate\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"title\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"issuingOrganization\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"issueDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"expirationDate\": {\n \"anyOf\": [{ \"$ref\": \"#/$defs/YearMonth\" }, { \"type\": \"null\" }],\n \"description\": \"null = explicitly 'no expiration'. Omit if unknown/unstated.\"\n },\n \"credentialId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 100,\n \"description\": \"License or certificate number. Public exposure controlled by meta.privacy.hideCredentialIds.\"\n },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Membership\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"organization\", \"startDate\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"organization\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"role\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"startDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"endDate\": {\n \"anyOf\": [{ \"$ref\": \"#/$defs/YearMonth\" }, { \"type\": \"null\" }],\n \"description\": \"null = ongoing. Omit if unknown.\"\n },\n \"isCurrent\": { \"type\": \"boolean\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Volunteering\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"organization\", \"role\", \"startDate\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"organization\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"role\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"cause\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"startDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"endDate\": {\n \"anyOf\": [{ \"$ref\": \"#/$defs/YearMonth\" }, { \"type\": \"null\" }]\n },\n \"isCurrent\": { \"type\": \"boolean\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Honor\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"title\", \"issuer\", \"date\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"title\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"issuer\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"date\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Education\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"institution\", \"startDate\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"institution\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"degree\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"fieldOfStudy\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"grade\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 50,\n \"description\": \"Free-form grade / class / GPA. Public exposure controlled by meta.privacy.hideEducationGrades.\"\n },\n \"startDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"endDate\": {\n \"anyOf\": [{ \"$ref\": \"#/$defs/YearMonth\" }, { \"type\": \"null\" }],\n \"description\": \"null = currently enrolled.\"\n },\n \"isCurrent\": { \"type\": \"boolean\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Publication\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"title\", \"date\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"title\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"publisher\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"date\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"doi\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 200,\n \"description\": \"DOI identifier (e.g. '10.1145/3548643.3548644'). The full URL goes in 'url'.\"\n },\n \"coAuthors\": {\n \"type\": \"array\",\n \"maxItems\": 50,\n \"items\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 100 },\n \"description\": \"Co-author names in original script. Excludes the profile owner.\"\n },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Language\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"language\", \"proficiency\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"language\": { \"$ref\": \"#/$defs/LocaleTag\" },\n \"displayName\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"proficiency\": {\n \"type\": \"string\",\n \"enum\": [\"native\", \"fluent\", \"professional\", \"intermediate\", \"basic\"],\n \"description\": \"LinkedIn-compatible 5-level proficiency.\"\n },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Course\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"title\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"title\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"provider\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"courseNumber\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 50 },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"completionDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"certificateUrl\": { \"$ref\": \"#/$defs/Url\" },\n \"relatedEducationId\": {\n \"$ref\": \"#/$defs/Slug\",\n \"description\": \"Optional reference to an education[].id (e.g. for university coursework).\"\n },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Patent\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"title\", \"patentNumber\", \"status\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"title\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"patentNumber\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 100 },\n \"office\": {\n \"type\": \"string\",\n \"maxLength\": 100,\n \"description\": \"Patent office name (e.g. 'USPTO', 'JPO', 'EPO').\"\n },\n \"status\": {\n \"type\": \"string\",\n \"enum\": [\"pending\", \"issued\", \"expired\", \"abandoned\"]\n },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"filingDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"grantDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"coInventors\": {\n \"type\": \"array\",\n \"maxItems\": 20,\n \"items\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 100 }\n },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"TestScore\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"title\", \"score\", \"date\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"title\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"score\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 50,\n \"description\": \"Free-form score string (e.g. '112 / 120', '330', 'N1 Pass', or a percentile). The validator does not interpret its contents.\"\n },\n \"date\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"relatedEducationId\": {\n \"$ref\": \"#/$defs/Slug\",\n \"description\": \"Optional reference to an education[].id (e.g. for a university course exam).\"\n },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Recommendation\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"body\", \"author\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"body\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"author\": { \"$ref\": \"#/$defs/RecommendationAuthor\" },\n \"relationship\": {\n \"$ref\": \"#/$defs/LocalizedTitle\",\n \"description\": \"How the recommender relates to the profile owner (e.g. 'managed directly', 'worked together').\"\n },\n \"date\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"relatedCareerId\": {\n \"$ref\": \"#/$defs/Slug\",\n \"description\": \"Optional reference to a careers[].id (the position the recommendation pertains to).\"\n },\n \"relatedEducationId\": {\n \"$ref\": \"#/$defs/Slug\",\n \"description\": \"Optional reference to an education[].id (e.g. a recommendation from a professor).\"\n },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"RecommendationAuthor\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"name\"],\n \"properties\": {\n \"name\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 100,\n \"description\": \"Recommender's name, in its original script. Owner-curated; takuhon does not verify it.\"\n },\n \"headline\": {\n \"$ref\": \"#/$defs/LocalizedTitle\",\n \"description\": \"Recommender's title / role / organization at the time of the recommendation.\"\n },\n \"url\": {\n \"$ref\": \"#/$defs/Url\",\n \"description\": \"Link to the recommender's profile, for external verification by the reader.\"\n }\n }\n }\n }\n}\n","/**\n * Re-exports the canonical JSON Schema for takuhon profiles.\n *\n * The schema source of truth lives at `packages/core/takuhon.schema.json`\n * (also distributed via the `@takuhon/core/schema.json` sub-path). This module\n * is the convenient ESM-side entry point for consumers that want to feed it\n * directly to a JSON Schema validator (e.g. Ajv) without a filesystem read.\n */\n\nimport schemaJson from '../takuhon.schema.json' with { type: 'json' };\n\nexport const schema = schemaJson;\nexport type Schema = typeof schemaJson;\n","/**\n * Schema validation for takuhon profile documents.\n *\n * Compiles the canonical {@link import('../takuhon.schema.json')} once at module\n * load and exposes a Result-style {@link validate} that returns either the\n * narrowed {@link Takuhon} value or a list of structured {@link ValidationError}s.\n * The validator is the canonical correctness boundary inside `@takuhon/core`:\n * `normalize` (commit 3) and the API layer (commit 11+) both rely on this\n * function to know the shape they are working with.\n *\n * Design notes:\n * - Returns a discriminated union rather than throwing so callers (CLI,\n * normalize, RFC 7807 Problem Details adapters) can route errors however they\n * like without paying for stack capture on every failure.\n * - Errors carry the RFC 6901 JSON Pointer of the offending value plus the\n * failing Ajv keyword, so consumers can render messages or look up the\n * relevant Spec section without leaking Ajv-specific types.\n * - The Ajv 2020 build is used because the schema declares\n * `$schema: \"https://json-schema.org/draft/2020-12/schema\"`.\n */\n\nimport type { ErrorObject } from 'ajv';\nimport Ajv2020 from 'ajv/dist/2020.js';\nimport addFormats from 'ajv-formats';\n\nimport { schema } from './schema.js';\nimport type { Takuhon } from './types.js';\n\n/**\n * Schema versions this build of `@takuhon/core` accepts directly.\n *\n * The migration registry (Phase 1 commit 6+) will translate older `schemaVersion`\n * values into the current one before validation runs, so this list reflects the\n * versions whose JSON Schema this package literally bundles, not the full\n * support window seen by end users.\n */\nexport const SUPPORTED_SCHEMA_VERSIONS = ['0.1.0', '0.2.0', '0.3.0', '0.4.0'] as const;\n\n/**\n * A single validation failure.\n *\n * The shape is intentionally schema-agnostic: an API layer can adapt it into an\n * RFC 7807 Problem Details payload, a CLI can render the message, and a future\n * spec-section lookup table can join on {@link pointer} to surface\n * documentation references. A `specSection` field will be added in a later\n * commit; this minimal surface is what commit 2 ships.\n */\nexport interface ValidationError {\n /** RFC 6901 JSON Pointer to the offending value, e.g. `\"/links/4/iconUrl\"`. */\n pointer: string;\n /** Human-readable failure description (sourced from Ajv when available). */\n message: string;\n /**\n * The schema keyword that failed: `'required'`, `'enum'`, `'pattern'`,\n * `'additionalProperties'`, `'format'`, `'maxItems'`, `'maxLength'`, etc.\n * The value `'schemaVersion'` is reserved for documents whose\n * `schemaVersion` lies outside {@link SUPPORTED_SCHEMA_VERSIONS}.\n */\n keyword: string;\n /** JSON Pointer into the schema for the failing rule, e.g. `\"#/$defs/Link/required\"`. */\n schemaPointer?: string;\n}\n\n/** Result of {@link validate}. Narrow on `ok` to access `data` or `errors`. */\nexport type ValidationResult =\n | { ok: true; data: Takuhon }\n | { ok: false; errors: ValidationError[] };\n\nconst ajv = new Ajv2020({\n allErrors: true,\n strict: true,\n});\naddFormats(ajv);\n\n// Per design decision #5 we skip `JSONSchemaType<Takuhon>` and let Ajv compile\n// the schema object as-is; the `<Takuhon>` type argument only records the\n// validated result type for downstream narrowing.\nconst compiled = ajv.compile<Takuhon>(schema);\n\n/**\n * Validate an arbitrary value against the bundled takuhon schema.\n *\n * @param data unknown JSON-like value (typically parsed from a `takuhon.json` file)\n * @returns A discriminated result. On success `data` is narrowed to {@link Takuhon};\n * on failure `errors` is a non-empty list of {@link ValidationError}s.\n */\nexport function validate(data: unknown): ValidationResult {\n // Pre-Ajv gate: reject anything that is not a plain object so callers get a\n // clearer top-level error than Ajv's cascade of \"must be object\" / property\n // failures when handed an array, null, or a primitive.\n if (typeof data !== 'object' || data === null || Array.isArray(data)) {\n return {\n ok: false,\n errors: [\n {\n pointer: '',\n message: 'takuhon.json must be a JSON object.',\n keyword: 'type',\n },\n ],\n };\n }\n\n // Pre-Ajv gate: reject documents whose schemaVersion sits outside the\n // supported window with a dedicated keyword. Migration (commit 6+) will\n // translate older versions into the current one before reaching this point.\n const candidate = data as { schemaVersion?: unknown };\n if (typeof candidate.schemaVersion === 'string' && !isSupportedVersion(candidate.schemaVersion)) {\n return {\n ok: false,\n errors: [\n {\n pointer: '/schemaVersion',\n message: `schemaVersion \"${candidate.schemaVersion}\" is not in the supported window (${SUPPORTED_SCHEMA_VERSIONS.join(\n ', ',\n )}).`,\n keyword: 'schemaVersion',\n },\n ],\n };\n }\n\n if (compiled(data)) {\n // The schema marks several top-level arrays as optional for back-compat\n // (the nine added in 0.2.0, `testScores` in 0.3.0, and `recommendations`\n // in 0.4.0). The TypeScript `Takuhon` shape requires them so\n // downstream code never has to check for `undefined`. We clone the\n // caller's input before coercing so a successful validate() never\n // mutates the original — callers can keep referencing the value they\n // passed in. JS preserves insertion order, so new keys land at the end\n // of the cloned object; `normalize()` is responsible for canonical\n // field order.\n const cloned = JSON.parse(JSON.stringify(data)) as Takuhon;\n coerceMissingArrays(cloned);\n\n // Post-Ajv check: `languages[].language` uniqueness. JSON Schema\n // `uniqueItems` only catches whole-object duplicates and cannot enforce\n // by-key uniqueness, so we walk the array here and reject duplicates as\n // a synthetic ValidationError.\n const duplicate = findDuplicateLanguage(cloned.languages);\n if (duplicate !== undefined) {\n return {\n ok: false,\n errors: [\n {\n pointer: `/languages/${duplicate.index}/language`,\n message: `Duplicate languages[].language value \"${duplicate.tag}\" — each entry must declare a unique BCP-47 tag.`,\n keyword: 'uniqueItems',\n },\n ],\n };\n }\n\n return { ok: true, data: cloned };\n }\n\n return {\n ok: false,\n errors: (compiled.errors ?? []).map(toValidationError),\n };\n}\n\nconst COERCED_ARRAY_KEYS = [\n 'certifications',\n 'memberships',\n 'volunteering',\n 'honors',\n 'education',\n 'publications',\n 'languages',\n 'courses',\n 'patents',\n 'testScores',\n 'recommendations',\n] as const;\n\nfunction coerceMissingArrays(data: Takuhon): void {\n const bag = data as unknown as Record<string, unknown>;\n for (const key of COERCED_ARRAY_KEYS) {\n if (!Array.isArray(bag[key])) {\n bag[key] = [];\n }\n }\n}\n\nfunction findDuplicateLanguage(\n languages: Takuhon['languages'],\n): { index: number; tag: string } | undefined {\n const seen = new Map<string, number>();\n for (let i = 0; i < languages.length; i++) {\n const entry = languages[i];\n if (entry === undefined) continue;\n const key = entry.language.toLowerCase();\n if (seen.has(key)) return { index: i, tag: entry.language };\n seen.set(key, i);\n }\n return undefined;\n}\n\nfunction isSupportedVersion(value: string): boolean {\n return (SUPPORTED_SCHEMA_VERSIONS as readonly string[]).includes(value);\n}\n\nfunction toValidationError(err: ErrorObject): ValidationError {\n let pointer = err.instancePath;\n\n if (err.keyword === 'required') {\n const missing = (err.params as { missingProperty?: unknown }).missingProperty;\n if (typeof missing === 'string') {\n pointer = `${err.instancePath}/${escapePointerSegment(missing)}`;\n }\n } else if (err.keyword === 'additionalProperties') {\n const extra = (err.params as { additionalProperty?: unknown }).additionalProperty;\n if (typeof extra === 'string') {\n pointer = `${err.instancePath}/${escapePointerSegment(extra)}`;\n }\n }\n\n return {\n pointer,\n message: err.message ?? 'Validation failed.',\n keyword: err.keyword,\n schemaPointer: err.schemaPath ? err.schemaPath : undefined,\n };\n}\n\n/** Escape a JSON Pointer segment per RFC 6901 (~ becomes ~0, / becomes ~1). */\nfunction escapePointerSegment(segment: string): string {\n return segment.replace(/~/g, '~0').replace(/\\//g, '~1');\n}\n","/**\n * Canonicalize a {@link Takuhon} document into the form downstream consumers\n * (`@takuhon/api`, `@takuhon/ui`, `@takuhon/jsonld`) can rely on without\n * re-checking shape invariants.\n *\n * Two transformations only:\n * - **Empty-entry cleanup** on every localized field (`LocalizedTitle` /\n * `LocalizedBody`): entries whose string value is empty or whitespace-only\n * are removed so that locale fallback works field-by-field. When the\n * cleanup leaves an optional localized map empty, the map itself is\n * removed (the schema requires `minProperties: 1`).\n * - **Stable sort by `order`** on every list field (`links`, `careers`,\n * `projects`, `skills`). Items without an `order` move to the end while\n * preserving their original relative position (ES2019 stable sort).\n *\n * Design notes:\n * - The input is deep-cloned via `structuredClone`; the original is never\n * mutated. Callers may safely keep a reference to the value they passed in.\n * - `normalize` does *not* canonicalize BCP-47 tag casing nor trim string\n * content. The first is covered by the schema's `propertyNames` pattern and\n * `resolveLocale`'s case-insensitive lookup; the second would silently rewrite\n * author input and is out of scope for Phase 1.\n * - `normalize(normalize(x))` deep-equals `normalize(x)` (idempotent), and the\n * output re-validates against `takuhon.schema.json`. Both invariants are\n * enforced by the unit tests.\n */\n\nimport type {\n LocalizedBody,\n LocalizedTitle,\n Takuhon,\n NormalizedTakuhon,\n Profile,\n} from './types.js';\n\n/**\n * Return a normalized copy of `data`.\n *\n * @param data A takuhon document that has already passed {@link validate}.\n * @returns A new {@link NormalizedTakuhon} with localized empties dropped and\n * list fields sorted by `order`.\n */\nexport function normalize(data: Takuhon): NormalizedTakuhon {\n // A takuhon document is structurally pure JSON (string/number/boolean/null +\n // plain objects / arrays — no Date, Map, Set, BigInt, or functions), so a\n // round-trip through JSON gives an equivalent deep clone without depending\n // on `structuredClone`'s global type declaration (which moves between TS\n // `lib.es2022.d.ts` and `lib.dom.d.ts` across TypeScript major releases).\n const out = JSON.parse(JSON.stringify(data)) as Takuhon;\n\n // Defensive: the schema marks several top-level arrays as optional for\n // back-compat (the nine added in 0.2.0, `testScores` in 0.3.0, and\n // `recommendations` in 0.4.0), so a stored older profile read from KV after\n // an upgrade may arrive here without them. The TypeScript `Takuhon` shape\n // requires them; coerce missing values to `[]` so downstream iteration\n // never trips on `undefined`. Idempotent: arrays already present are left\n // untouched.\n const bag = out as unknown as Record<string, unknown>;\n for (const key of NORMALIZED_ARRAYS) {\n if (!Array.isArray(bag[key])) {\n bag[key] = [];\n }\n }\n\n normalizeProfile(out.profile);\n\n for (const link of out.links) {\n cleanOptionalLocalized(link, 'label');\n }\n out.links = stableSortByOrder(out.links);\n\n for (const career of out.careers) {\n cleanRequiredLocalized(career.organization);\n cleanRequiredLocalized(career.role);\n cleanOptionalLocalized(career, 'description');\n }\n out.careers = stableSortByOrder(out.careers);\n\n for (const project of out.projects) {\n cleanRequiredLocalized(project.title);\n cleanOptionalLocalized(project, 'description');\n }\n out.projects = stableSortByOrder(out.projects);\n\n out.skills = stableSortByOrder(out.skills);\n\n for (const cert of out.certifications) {\n cleanRequiredLocalized(cert.title);\n cleanRequiredLocalized(cert.issuingOrganization);\n }\n out.certifications = stableSortByOrder(out.certifications);\n\n for (const m of out.memberships) {\n cleanRequiredLocalized(m.organization);\n cleanOptionalLocalized(m, 'role');\n cleanOptionalLocalized(m, 'description');\n }\n out.memberships = stableSortByOrder(out.memberships);\n\n for (const v of out.volunteering) {\n cleanRequiredLocalized(v.organization);\n cleanRequiredLocalized(v.role);\n cleanOptionalLocalized(v, 'cause');\n cleanOptionalLocalized(v, 'description');\n }\n out.volunteering = stableSortByOrder(out.volunteering);\n\n for (const h of out.honors) {\n cleanRequiredLocalized(h.title);\n cleanRequiredLocalized(h.issuer);\n cleanOptionalLocalized(h, 'description');\n }\n out.honors = stableSortByOrder(out.honors);\n\n for (const e of out.education) {\n cleanRequiredLocalized(e.institution);\n cleanOptionalLocalized(e, 'degree');\n cleanOptionalLocalized(e, 'fieldOfStudy');\n cleanOptionalLocalized(e, 'description');\n }\n out.education = stableSortByOrder(out.education);\n\n for (const p of out.publications) {\n cleanRequiredLocalized(p.title);\n cleanOptionalLocalized(p, 'publisher');\n cleanOptionalLocalized(p, 'description');\n }\n out.publications = stableSortByOrder(out.publications);\n\n for (const l of out.languages) {\n cleanOptionalLocalized(l, 'displayName');\n }\n out.languages = stableSortByOrder(out.languages);\n\n for (const c of out.courses) {\n cleanRequiredLocalized(c.title);\n cleanOptionalLocalized(c, 'provider');\n cleanOptionalLocalized(c, 'description');\n }\n out.courses = stableSortByOrder(out.courses);\n\n for (const p of out.patents) {\n cleanRequiredLocalized(p.title);\n cleanOptionalLocalized(p, 'description');\n }\n out.patents = stableSortByOrder(out.patents);\n\n for (const t of out.testScores) {\n cleanRequiredLocalized(t.title);\n cleanOptionalLocalized(t, 'description');\n }\n out.testScores = stableSortByOrder(out.testScores);\n\n for (const r of out.recommendations) {\n cleanRequiredLocalized(r.body);\n cleanOptionalLocalized(r, 'relationship');\n cleanOptionalLocalized(r.author, 'headline');\n }\n out.recommendations = stableSortByOrder(out.recommendations);\n\n return out;\n}\n\nfunction normalizeProfile(profile: Profile): void {\n cleanRequiredLocalized(profile.displayName);\n cleanOptionalLocalized(profile, 'tagline');\n cleanOptionalLocalized(profile, 'bio');\n if (profile.avatar) {\n cleanOptionalLocalized(profile.avatar, 'alt');\n }\n if (profile.location) {\n cleanOptionalLocalized(profile.location, 'locality');\n cleanOptionalLocalized(profile.location, 'display');\n }\n}\n\n/** Remove empty / whitespace-only entries from a required localized map in place. */\nfunction cleanRequiredLocalized(map: LocalizedTitle | LocalizedBody): void {\n for (const key of Object.keys(map)) {\n const value = map[key];\n if (value === undefined || value.trim() === '') {\n delete map[key];\n }\n }\n}\n\n/**\n * Remove empty / whitespace-only entries from an optional localized map. When\n * the resulting map is empty, the property is removed from its parent so the\n * document remains schema-valid (`LocalizedTitle` / `LocalizedBody` require\n * `minProperties: 1`).\n */\nfunction cleanOptionalLocalized<\n K extends string,\n T extends Partial<Record<K, LocalizedTitle | LocalizedBody>>,\n>(parent: T, key: K): void {\n const map = parent[key];\n if (!map) return;\n for (const k of Object.keys(map)) {\n const value = map[k];\n if (value === undefined || value.trim() === '') {\n delete map[k];\n }\n }\n if (Object.keys(map).length === 0) {\n delete parent[key];\n }\n}\n\n/** Stable sort items by ascending `order`; entries without `order` go last. */\nfunction stableSortByOrder<T extends { order?: number }>(items: T[]): T[] {\n return items.slice().sort((a, b) => {\n const ao = a.order ?? Number.POSITIVE_INFINITY;\n const bo = b.order ?? Number.POSITIVE_INFINITY;\n return ao - bo;\n });\n}\n\nconst NORMALIZED_ARRAYS = [\n 'certifications',\n 'memberships',\n 'volunteering',\n 'honors',\n 'education',\n 'publications',\n 'languages',\n 'courses',\n 'patents',\n 'testScores',\n 'recommendations',\n] as const;\n","/**\n * BCP-47 locale-tag helpers shared by `normalize()` and `resolveLocale()`.\n *\n * These functions intentionally do not depend on `Intl.Locale`: the schema's\n * `propertyNames` pattern already guarantees structural validity for tags that\n * have passed validation, so this module only needs string-level operations\n * (case-insensitive lookup, primary-subtag fallback, simple regex shape check).\n * Keeping the implementation dependency-free also avoids platform differences\n * between Node, Workers, and modern browsers.\n */\n\n/** Same shape as `takuhon.schema.json`'s `propertyNames` for localized maps. */\nconst BCP47_PATTERN = /^[a-zA-Z]{2,3}(-[a-zA-Z0-9]+)*$/;\n\n/**\n * Return whether a string has the structural shape of a BCP-47 tag accepted\n * by `takuhon.schema.json`. This is a syntactic check only — `'zz'` passes\n * because it matches the regex even though it is not a registered subtag.\n * Semantic validity (registered language / region) is intentionally out of\n * scope; consumers that want it should compose `Intl.Locale` on top.\n */\nexport function isValidBcp47(tag: string): boolean {\n return BCP47_PATTERN.test(tag);\n}\n\n/**\n * Expand a tag into a list of progressively shorter candidates by dropping\n * trailing subtags, e.g. `'zh-Hant-TW' → ['zh-Hant-TW', 'zh-Hant', 'zh']`.\n * Returns the input unchanged for single-subtag inputs (`'en' → ['en']`),\n * and returns `[]` for tags that do not match the BCP-47 shape.\n */\nexport function expandRegional(tag: string): string[] {\n if (!isValidBcp47(tag)) return [];\n const parts = tag.split('-');\n const out: string[] = [];\n for (let i = parts.length; i >= 1; i--) {\n out.push(parts.slice(0, i).join('-'));\n }\n return out;\n}\n\n/** Compare two locale tags ignoring ASCII case (`'EN-us'` matches `'en-US'`). */\nexport function localeMatches(a: string, b: string): boolean {\n return a.toLowerCase() === b.toLowerCase();\n}\n\n/**\n * Look up a value from a locale-keyed map ignoring ASCII case.\n *\n * BCP-47 tags use canonical casing (`zh-Hant`, `pt-BR`) but the spec asks for\n * case-insensitive comparison so consumers can query with `EN-us` or `EN-US`\n * regardless of how the document was authored.\n */\nexport function lookupCaseInsensitive<T>(\n map: Record<string, T> | undefined,\n key: string,\n): T | undefined {\n if (!map) return undefined;\n const direct = map[key];\n if (direct !== undefined) return direct;\n const lower = key.toLowerCase();\n for (const k of Object.keys(map)) {\n if (k.toLowerCase() === lower) return map[k];\n }\n return undefined;\n}\n","/**\n * Reduce a multi-locale {@link Takuhon} document to a single requested locale.\n *\n * Builds a flat candidate chain from the function arguments and `data.settings`,\n * expanding each entry's regional subtag (e.g. `'en-US' → ['en-US', 'en']`),\n * deduplicating case-insensitively, then walks the chain **per field**. The\n * first candidate whose value is non-blank wins for that field; an empty entry\n * (`\"\"` / whitespace-only) falls through to the next candidate just like a\n * missing entry. This matches the spec semantics in [api.md §3.4] where empty\n * values are equivalent to absence.\n *\n * Design notes:\n * - Function arguments (`locale`, `fallbackLocale`) take precedence over\n * `settings.*`, in line with the spec's 7-tier list: HTTP-derived locales\n * (#1-#4) are resolved upstream by `@takuhon/api` and arrive here as\n * `locale` / `fallbackLocale`; `settings.defaultLocale` (#5),\n * `settings.fallbackLocale` (#6), and `settings.availableLocales[0]` (#7)\n * fill the tail.\n * - Invalid tags (`'zz_invalid'`, `'_'`, etc.) are silently dropped rather\n * than throwing. Resolution is best-effort: throwing on a malformed\n * `?lang=` query would push error handling responsibilities back into the\n * API layer for a recoverable case.\n * - A final rescue step appends every `availableLocales` entry so a request\n * with no matching candidate still produces a populated document. If even\n * that fails (only possible for hand-crafted inputs that bypassed\n * `validate`), required strings fall back to `''` and the caller's tests\n * catch the document-level regression.\n * - `resolvedLocale` records the tag that produced `profile.displayName`,\n * which is the field most consumers expose as the canonical locale of the\n * response (e.g. `meta.locale` in API responses, `<html lang>` in UI).\n */\n\nimport { expandRegional, isValidBcp47, lookupCaseInsensitive } from './locale-tag.js';\nimport type {\n Address,\n Avatar,\n Career,\n Certification,\n Course,\n Education,\n Honor,\n Language,\n Link,\n LocaleTag,\n LocalizedAddress,\n LocalizedAvatar,\n LocalizedBody,\n LocalizedCareer,\n LocalizedCertification,\n LocalizedCourse,\n LocalizedEducation,\n LocalizedHonor,\n LocalizedLanguage,\n LocalizedLink,\n LocalizedMembership,\n LocalizedPatent,\n LocalizedProfile,\n LocalizedProject,\n LocalizedPublication,\n LocalizedRecommendation,\n LocalizedRecommendationAuthor,\n LocalizedTakuhon,\n LocalizedTestScore,\n LocalizedTitle,\n LocalizedVolunteering,\n Membership,\n Patent,\n Profile,\n Project,\n Publication,\n Recommendation,\n RecommendationAuthor,\n Takuhon,\n TestScore,\n Volunteering,\n} from './types.js';\n\n/**\n * Resolve a takuhon document to a single locale.\n *\n * @param data A takuhon document (validated; ideally normalized first).\n * @param locale Caller-resolved request locale (e.g. from `?lang=` or\n * `Accept-Language`). Invalid tags are ignored.\n * @param fallbackLocale Caller-supplied secondary candidate when `locale`\n * misses. Invalid tags are ignored.\n */\nexport function resolveLocale(\n data: Takuhon,\n locale?: string,\n fallbackLocale?: string,\n): LocalizedTakuhon {\n const candidates = buildCandidates(data, locale, fallbackLocale);\n const displayPick = pickLocalizedWithTag(data.profile.displayName, candidates);\n\n return {\n schemaVersion: data.schemaVersion,\n profile: resolveProfile(data.profile, candidates, displayPick?.value ?? ''),\n links: data.links.map((l) => resolveLink(l, candidates)),\n careers: data.careers.map((c) => resolveCareer(c, candidates)),\n projects: data.projects.map((p) => resolveProject(p, candidates)),\n skills: data.skills,\n certifications: data.certifications.map((c) => resolveCertification(c, candidates)),\n memberships: data.memberships.map((m) => resolveMembership(m, candidates)),\n volunteering: data.volunteering.map((v) => resolveVolunteering(v, candidates)),\n honors: data.honors.map((h) => resolveHonor(h, candidates)),\n education: data.education.map((e) => resolveEducation(e, candidates)),\n publications: data.publications.map((p) => resolvePublication(p, candidates)),\n languages: data.languages.map((l) => resolveLanguage(l, candidates)),\n courses: data.courses.map((c) => resolveCourse(c, candidates)),\n patents: data.patents.map((p) => resolvePatent(p, candidates)),\n testScores: data.testScores.map((t) => resolveTestScore(t, candidates)),\n recommendations: data.recommendations.map((r) => resolveRecommendation(r, candidates)),\n contact: data.contact,\n settings: data.settings,\n meta: data.meta,\n resolvedLocale: displayPick?.tag ?? candidates[0] ?? '',\n };\n}\n\nfunction buildCandidates(\n data: Takuhon,\n locale: string | undefined,\n fallbackLocale: string | undefined,\n): LocaleTag[] {\n const raw: string[] = [];\n if (locale !== undefined) raw.push(...expandRegional(locale));\n if (fallbackLocale !== undefined) raw.push(...expandRegional(fallbackLocale));\n raw.push(...expandRegional(data.settings.defaultLocale));\n if (data.settings.fallbackLocale !== undefined) {\n raw.push(...expandRegional(data.settings.fallbackLocale));\n }\n for (const tag of data.settings.availableLocales) {\n raw.push(...expandRegional(tag));\n }\n return dedupCaseInsensitive(raw);\n}\n\nfunction dedupCaseInsensitive(tags: string[]): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const tag of tags) {\n if (!isValidBcp47(tag)) continue;\n const lower = tag.toLowerCase();\n if (seen.has(lower)) continue;\n seen.add(lower);\n out.push(tag);\n }\n return out;\n}\n\nfunction pickLocalizedWithTag(\n field: LocalizedTitle | LocalizedBody | undefined,\n candidates: LocaleTag[],\n): { value: string; tag: LocaleTag } | undefined {\n if (!field) return undefined;\n for (const tag of candidates) {\n const hit = lookupCaseInsensitive(field, tag);\n if (hit !== undefined && hit.trim() !== '') {\n return { value: hit, tag };\n }\n }\n return undefined;\n}\n\nfunction pickLocalized(\n field: LocalizedTitle | LocalizedBody | undefined,\n candidates: LocaleTag[],\n): string | undefined {\n return pickLocalizedWithTag(field, candidates)?.value;\n}\n\nfunction resolveProfile(\n profile: Profile,\n candidates: LocaleTag[],\n displayName: string,\n): LocalizedProfile {\n const out: LocalizedProfile = { displayName };\n\n const tagline = pickLocalized(profile.tagline, candidates);\n if (tagline !== undefined) out.tagline = tagline;\n\n const bio = pickLocalized(profile.bio, candidates);\n if (bio !== undefined) out.bio = bio;\n\n if (profile.avatar) out.avatar = resolveAvatar(profile.avatar, candidates);\n if (profile.location) out.location = resolveAddress(profile.location, candidates);\n\n return out;\n}\n\nfunction resolveAvatar(avatar: Avatar, candidates: LocaleTag[]): LocalizedAvatar {\n const out: LocalizedAvatar = { url: avatar.url };\n const alt = pickLocalized(avatar.alt, candidates);\n if (alt !== undefined) out.alt = alt;\n return out;\n}\n\nfunction resolveAddress(address: Address, candidates: LocaleTag[]): LocalizedAddress {\n const out: LocalizedAddress = {};\n if (address.country !== undefined) out.country = address.country;\n if (address.region !== undefined) out.region = address.region;\n const locality = pickLocalized(address.locality, candidates);\n if (locality !== undefined) out.locality = locality;\n const display = pickLocalized(address.display, candidates);\n if (display !== undefined) out.display = display;\n return out;\n}\n\nfunction resolveLink(link: Link, candidates: LocaleTag[]): LocalizedLink {\n const label = pickLocalized(link.label, candidates);\n if (link.type === 'custom') {\n const out: LocalizedLink = {\n id: link.id,\n type: 'custom',\n url: link.url,\n iconUrl: link.iconUrl,\n };\n if (label !== undefined) out.label = label;\n if (link.featured !== undefined) out.featured = link.featured;\n if (link.order !== undefined) out.order = link.order;\n return out;\n }\n const out: LocalizedLink = {\n id: link.id,\n type: link.type,\n url: link.url,\n };\n if (label !== undefined) out.label = label;\n if (link.featured !== undefined) out.featured = link.featured;\n if (link.order !== undefined) out.order = link.order;\n if (link.iconUrl !== undefined) out.iconUrl = link.iconUrl;\n return out;\n}\n\nfunction resolveCareer(career: Career, candidates: LocaleTag[]): LocalizedCareer {\n const out: LocalizedCareer = {\n id: career.id,\n organization: pickLocalized(career.organization, candidates) ?? '',\n role: pickLocalized(career.role, candidates) ?? '',\n startDate: career.startDate,\n };\n const description = pickLocalized(career.description, candidates);\n if (description !== undefined) out.description = description;\n if (career.endDate !== undefined) out.endDate = career.endDate;\n if (career.isCurrent !== undefined) out.isCurrent = career.isCurrent;\n if (career.url !== undefined) out.url = career.url;\n if (career.order !== undefined) out.order = career.order;\n if (career.location) out.location = resolveAddress(career.location, candidates);\n return out;\n}\n\nfunction resolveProject(project: Project, candidates: LocaleTag[]): LocalizedProject {\n const out: LocalizedProject = {\n id: project.id,\n title: pickLocalized(project.title, candidates) ?? '',\n };\n const description = pickLocalized(project.description, candidates);\n if (description !== undefined) out.description = description;\n if (project.url !== undefined) out.url = project.url;\n if (project.tags !== undefined) out.tags = project.tags;\n if (project.relatedCareerId !== undefined) out.relatedCareerId = project.relatedCareerId;\n if (project.startDate !== undefined) out.startDate = project.startDate;\n if (project.endDate !== undefined) out.endDate = project.endDate;\n if (project.highlighted !== undefined) out.highlighted = project.highlighted;\n if (project.order !== undefined) out.order = project.order;\n return out;\n}\n\nfunction resolveCertification(\n cert: Certification,\n candidates: LocaleTag[],\n): LocalizedCertification {\n const out: LocalizedCertification = {\n id: cert.id,\n title: pickLocalized(cert.title, candidates) ?? '',\n issuingOrganization: pickLocalized(cert.issuingOrganization, candidates) ?? '',\n issueDate: cert.issueDate,\n };\n if (cert.expirationDate !== undefined) out.expirationDate = cert.expirationDate;\n if (cert.credentialId !== undefined) out.credentialId = cert.credentialId;\n if (cert.url !== undefined) out.url = cert.url;\n if (cert.order !== undefined) out.order = cert.order;\n return out;\n}\n\nfunction resolveMembership(membership: Membership, candidates: LocaleTag[]): LocalizedMembership {\n const out: LocalizedMembership = {\n id: membership.id,\n organization: pickLocalized(membership.organization, candidates) ?? '',\n startDate: membership.startDate,\n };\n const role = pickLocalized(membership.role, candidates);\n if (role !== undefined) out.role = role;\n const description = pickLocalized(membership.description, candidates);\n if (description !== undefined) out.description = description;\n if (membership.endDate !== undefined) out.endDate = membership.endDate;\n if (membership.isCurrent !== undefined) out.isCurrent = membership.isCurrent;\n if (membership.url !== undefined) out.url = membership.url;\n if (membership.order !== undefined) out.order = membership.order;\n return out;\n}\n\nfunction resolveVolunteering(v: Volunteering, candidates: LocaleTag[]): LocalizedVolunteering {\n const out: LocalizedVolunteering = {\n id: v.id,\n organization: pickLocalized(v.organization, candidates) ?? '',\n role: pickLocalized(v.role, candidates) ?? '',\n startDate: v.startDate,\n };\n const cause = pickLocalized(v.cause, candidates);\n if (cause !== undefined) out.cause = cause;\n const description = pickLocalized(v.description, candidates);\n if (description !== undefined) out.description = description;\n if (v.endDate !== undefined) out.endDate = v.endDate;\n if (v.isCurrent !== undefined) out.isCurrent = v.isCurrent;\n if (v.url !== undefined) out.url = v.url;\n if (v.order !== undefined) out.order = v.order;\n return out;\n}\n\nfunction resolveHonor(honor: Honor, candidates: LocaleTag[]): LocalizedHonor {\n const out: LocalizedHonor = {\n id: honor.id,\n title: pickLocalized(honor.title, candidates) ?? '',\n issuer: pickLocalized(honor.issuer, candidates) ?? '',\n date: honor.date,\n };\n const description = pickLocalized(honor.description, candidates);\n if (description !== undefined) out.description = description;\n if (honor.url !== undefined) out.url = honor.url;\n if (honor.order !== undefined) out.order = honor.order;\n return out;\n}\n\nfunction resolveEducation(edu: Education, candidates: LocaleTag[]): LocalizedEducation {\n const out: LocalizedEducation = {\n id: edu.id,\n institution: pickLocalized(edu.institution, candidates) ?? '',\n startDate: edu.startDate,\n };\n const degree = pickLocalized(edu.degree, candidates);\n if (degree !== undefined) out.degree = degree;\n const fieldOfStudy = pickLocalized(edu.fieldOfStudy, candidates);\n if (fieldOfStudy !== undefined) out.fieldOfStudy = fieldOfStudy;\n const description = pickLocalized(edu.description, candidates);\n if (description !== undefined) out.description = description;\n if (edu.grade !== undefined) out.grade = edu.grade;\n if (edu.endDate !== undefined) out.endDate = edu.endDate;\n if (edu.isCurrent !== undefined) out.isCurrent = edu.isCurrent;\n if (edu.url !== undefined) out.url = edu.url;\n if (edu.order !== undefined) out.order = edu.order;\n return out;\n}\n\nfunction resolvePublication(pub: Publication, candidates: LocaleTag[]): LocalizedPublication {\n const out: LocalizedPublication = {\n id: pub.id,\n title: pickLocalized(pub.title, candidates) ?? '',\n date: pub.date,\n };\n const publisher = pickLocalized(pub.publisher, candidates);\n if (publisher !== undefined) out.publisher = publisher;\n const description = pickLocalized(pub.description, candidates);\n if (description !== undefined) out.description = description;\n if (pub.url !== undefined) out.url = pub.url;\n if (pub.doi !== undefined) out.doi = pub.doi;\n if (pub.coAuthors !== undefined) out.coAuthors = pub.coAuthors;\n if (pub.order !== undefined) out.order = pub.order;\n return out;\n}\n\nfunction resolveLanguage(lang: Language, candidates: LocaleTag[]): LocalizedLanguage {\n const out: LocalizedLanguage = {\n id: lang.id,\n language: lang.language,\n proficiency: lang.proficiency,\n };\n const displayName = pickLocalized(lang.displayName, candidates);\n if (displayName !== undefined) out.displayName = displayName;\n if (lang.order !== undefined) out.order = lang.order;\n return out;\n}\n\nfunction resolveCourse(course: Course, candidates: LocaleTag[]): LocalizedCourse {\n const out: LocalizedCourse = {\n id: course.id,\n title: pickLocalized(course.title, candidates) ?? '',\n };\n const provider = pickLocalized(course.provider, candidates);\n if (provider !== undefined) out.provider = provider;\n if (course.courseNumber !== undefined) out.courseNumber = course.courseNumber;\n const description = pickLocalized(course.description, candidates);\n if (description !== undefined) out.description = description;\n if (course.completionDate !== undefined) out.completionDate = course.completionDate;\n if (course.certificateUrl !== undefined) out.certificateUrl = course.certificateUrl;\n if (course.relatedEducationId !== undefined) out.relatedEducationId = course.relatedEducationId;\n if (course.order !== undefined) out.order = course.order;\n return out;\n}\n\nfunction resolvePatent(patent: Patent, candidates: LocaleTag[]): LocalizedPatent {\n const out: LocalizedPatent = {\n id: patent.id,\n title: pickLocalized(patent.title, candidates) ?? '',\n patentNumber: patent.patentNumber,\n status: patent.status,\n };\n if (patent.office !== undefined) out.office = patent.office;\n const description = pickLocalized(patent.description, candidates);\n if (description !== undefined) out.description = description;\n if (patent.filingDate !== undefined) out.filingDate = patent.filingDate;\n if (patent.grantDate !== undefined) out.grantDate = patent.grantDate;\n if (patent.url !== undefined) out.url = patent.url;\n if (patent.coInventors !== undefined) out.coInventors = patent.coInventors;\n if (patent.order !== undefined) out.order = patent.order;\n return out;\n}\n\nfunction resolveTestScore(testScore: TestScore, candidates: LocaleTag[]): LocalizedTestScore {\n const out: LocalizedTestScore = {\n id: testScore.id,\n title: pickLocalized(testScore.title, candidates) ?? '',\n score: testScore.score,\n date: testScore.date,\n };\n const description = pickLocalized(testScore.description, candidates);\n if (description !== undefined) out.description = description;\n if (testScore.relatedEducationId !== undefined) {\n out.relatedEducationId = testScore.relatedEducationId;\n }\n if (testScore.url !== undefined) out.url = testScore.url;\n if (testScore.order !== undefined) out.order = testScore.order;\n return out;\n}\n\nfunction resolveRecommendation(\n recommendation: Recommendation,\n candidates: LocaleTag[],\n): LocalizedRecommendation {\n const out: LocalizedRecommendation = {\n id: recommendation.id,\n body: pickLocalized(recommendation.body, candidates) ?? '',\n author: resolveRecommendationAuthor(recommendation.author, candidates),\n };\n const relationship = pickLocalized(recommendation.relationship, candidates);\n if (relationship !== undefined) out.relationship = relationship;\n if (recommendation.date !== undefined) out.date = recommendation.date;\n if (recommendation.relatedCareerId !== undefined) {\n out.relatedCareerId = recommendation.relatedCareerId;\n }\n if (recommendation.relatedEducationId !== undefined) {\n out.relatedEducationId = recommendation.relatedEducationId;\n }\n if (recommendation.order !== undefined) out.order = recommendation.order;\n return out;\n}\n\nfunction resolveRecommendationAuthor(\n author: RecommendationAuthor,\n candidates: LocaleTag[],\n): LocalizedRecommendationAuthor {\n const out: LocalizedRecommendationAuthor = { name: author.name };\n const headline = pickLocalized(author.headline, candidates);\n if (headline !== undefined) out.headline = headline;\n if (author.url !== undefined) out.url = author.url;\n return out;\n}\n","/**\n * Generate Schema.org JSON-LD from a {@link LocalizedTakuhon} document.\n *\n * Emits a `ProfilePage` whose `mainEntity` is the `Person` described by the\n * input. Mapping rules follow the published schema.org mapping spec; the\n * relevant invariants are exercised by the unit tests.\n *\n * Design notes:\n * - Input is the output of `resolveLocale()`, so every localized field is\n * already a single string. No locale fallback happens here.\n * - All optional keys are omitted (not set to `null` / `undefined`) when their\n * source value is absent or empty, so consumers can shallow-merge or\n * `JSON.stringify` the result without post-processing.\n * - The canonical URL surfaced as `ProfilePage.url`, `Person.@id`, and\n * `Person.url` is derived from a single `links[]` entry: `type: 'website'`\n * with `featured: true`. The first match wins (stable after `normalize()`).\n * When no such link exists the three URL-bearing keys are omitted entirely;\n * no placeholder is fabricated.\n * - `profile.tagline` is intentionally not surfaced. `description` carries\n * `profile.bio` only, matching the spec exemplar. Phase 2 may revisit.\n * - `contact.email` is surfaced only when `contact.showEmail === true`\n * (privacy by default).\n * - URLs pass through verbatim. Relative paths in the input remain relative\n * in the output; absolutization is the API/UI layer's responsibility.\n * - Field insertion order on each emitted object is fixed so\n * `JSON.stringify(result)` is deterministic for a given input.\n */\n\nimport type {\n Contact,\n LinkType,\n LocalizedAddress,\n LocalizedAvatar,\n LocalizedCareer,\n LocalizedCertification,\n LocalizedCourse,\n LocalizedEducation,\n LocalizedHonor,\n LocalizedLanguage,\n LocalizedLink,\n LocalizedMembership,\n LocalizedPatent,\n LocalizedProject,\n LocalizedPublication,\n LocalizedTakuhon,\n LocalizedVolunteering,\n Skill,\n} from './types.js';\n\n/**\n * `links[].type` values that count as identity-bearing for the purpose of\n * `Person.sameAs`. `email`, `rss`, and `custom` are excluded: they either\n * carry no identity assertion (`custom`) or are not a profile URL on a\n * third-party platform (`email`, `rss`).\n */\nconst SAMEAS_IDENTITY_TYPES: ReadonlySet<LinkType> = new Set<LinkType>([\n 'github',\n 'gitlab',\n 'linkedin',\n 'x',\n 'mastodon',\n 'bluesky',\n 'instagram',\n 'youtube',\n 'threads',\n 'facebook',\n 'website',\n 'blog',\n]);\n\n/**\n * Build the `Person` JSON-LD object for `data`.\n *\n * @param data A locale-resolved takuhon document.\n * @returns A Schema.org `Person` object. `@context` is included so the\n * returned object is valid as a standalone JSON-LD document.\n */\nexport function generatePersonJsonLd(data: LocalizedTakuhon): object {\n const person = buildPerson(data, deriveCanonicalUrl(data));\n return { '@context': 'https://schema.org', ...person };\n}\n\n/**\n * Build the `ProfilePage` JSON-LD object for `data`, with `Person` inlined\n * as `mainEntity`.\n *\n * @param data A locale-resolved takuhon document.\n */\nexport function generateProfilePageJsonLd(data: LocalizedTakuhon): object {\n const canonicalUrl = deriveCanonicalUrl(data);\n const person = buildPerson(data, canonicalUrl);\n\n const out: Record<string, unknown> = {};\n out['@context'] = 'https://schema.org';\n out['@type'] = 'ProfilePage';\n if (canonicalUrl !== undefined) out.url = canonicalUrl;\n out.inLanguage = data.resolvedLocale;\n if (data.meta.createdAt !== undefined) out.dateCreated = data.meta.createdAt;\n if (data.meta.updatedAt !== undefined) out.dateModified = data.meta.updatedAt;\n if (data.profile.avatar !== undefined) out.primaryImageOfPage = data.profile.avatar.url;\n out.mainEntity = person;\n return out;\n}\n\n/**\n * Build the array of JSON-LD objects to embed in a single\n * `<script type=\"application/ld+json\">` tag.\n *\n * Phase 1 emits a single-element array containing the `ProfilePage`; the\n * `Person` is inlined there as `mainEntity`. The array shape leaves room\n * for later additions (e.g. `WebSite`) without changing the public surface.\n */\nexport function generateJsonLd(data: LocalizedTakuhon): object[] {\n return [generateProfilePageJsonLd(data)];\n}\n\nfunction deriveCanonicalUrl(data: LocalizedTakuhon): string | undefined {\n const featured = data.links.find((l) => l.type === 'website' && l.featured === true);\n return featured?.url;\n}\n\nfunction buildPerson(data: LocalizedTakuhon, canonicalUrl: string | undefined): object {\n const {\n profile,\n careers,\n projects,\n links,\n skills,\n contact,\n certifications,\n memberships,\n volunteering,\n honors,\n education,\n publications,\n languages,\n courses,\n patents,\n } = data;\n\n const out: Record<string, unknown> = {};\n out['@type'] = 'Person';\n if (canonicalUrl !== undefined) out['@id'] = `${canonicalUrl}#person`;\n out.name = profile.displayName;\n if (profile.bio !== undefined) out.description = profile.bio;\n\n const image = buildImage(profile.avatar);\n if (image !== undefined) out.image = image;\n\n if (canonicalUrl !== undefined) out.url = canonicalUrl;\n\n const { current, past } = partitionCareers(careers);\n const roleFields = buildCurrentRoleFields(current);\n if (roleFields.jobTitle !== undefined) out.jobTitle = roleFields.jobTitle;\n if (roleFields.worksFor !== undefined) out.worksFor = roleFields.worksFor;\n\n const address = buildAddress(profile.location);\n if (address !== undefined) out.address = address;\n\n const email = buildEmail(contact);\n if (email !== undefined) out.email = email;\n\n const knowsAbout = buildKnowsAbout(skills);\n if (knowsAbout !== undefined) out.knowsAbout = knowsAbout;\n\n const knowsLanguage = buildKnowsLanguage(languages);\n if (knowsLanguage !== undefined) out.knowsLanguage = knowsLanguage;\n\n const hasCredential = buildCredentials(certifications);\n if (hasCredential !== undefined) out.hasCredential = hasCredential;\n\n const memberOf = buildMemberOf(memberships);\n if (memberOf !== undefined) out.memberOf = memberOf;\n\n const alumniOf = buildAlumniOf(education);\n if (alumniOf !== undefined) out.alumniOf = alumniOf;\n\n const award = buildAwards(honors);\n if (award !== undefined) out.award = award;\n\n const sameAs = buildSameAs(links);\n if (sameAs !== undefined) out.sameAs = sameAs;\n\n const subjectOf = [\n ...buildPastRoles(past),\n ...buildProjects(projects),\n ...buildVolunteeringRoles(volunteering),\n ...buildPublications(publications),\n ...buildCourses(courses),\n ...buildPatentWorks(patents),\n ];\n if (subjectOf.length > 0) out.subjectOf = subjectOf;\n\n return out;\n}\n\nfunction buildImage(avatar: LocalizedAvatar | undefined): object | undefined {\n if (!avatar) return undefined;\n const out: Record<string, unknown> = {};\n out['@type'] = 'ImageObject';\n out.url = avatar.url;\n if (avatar.alt !== undefined) out.caption = avatar.alt;\n return out;\n}\n\nfunction buildAddress(location: LocalizedAddress | undefined): object | undefined {\n if (!location) return undefined;\n const hasAny =\n location.country !== undefined ||\n location.region !== undefined ||\n location.locality !== undefined;\n if (!hasAny) return undefined;\n // `location.display` is intentionally not surfaced: it is a UI-facing\n // pre-formatted string and would duplicate the structured fields here.\n const out: Record<string, unknown> = {};\n out['@type'] = 'PostalAddress';\n if (location.country !== undefined) out.addressCountry = location.country;\n if (location.region !== undefined) out.addressRegion = location.region;\n if (location.locality !== undefined) out.addressLocality = location.locality;\n return out;\n}\n\nfunction partitionCareers(careers: LocalizedCareer[]): {\n current: LocalizedCareer[];\n past: LocalizedCareer[];\n} {\n const current: LocalizedCareer[] = [];\n const past: LocalizedCareer[] = [];\n for (const c of careers) {\n if (c.isCurrent === true) current.push(c);\n else past.push(c);\n }\n return { current, past };\n}\n\nfunction buildCurrentRoleFields(current: LocalizedCareer[]): {\n jobTitle?: string;\n worksFor?: object;\n} {\n const head = current[0];\n if (head === undefined) return {};\n const out: { jobTitle?: string; worksFor?: object } = {};\n if (head.role !== '') out.jobTitle = head.role;\n out.worksFor = buildWorksFor(head);\n return out;\n}\n\nfunction buildWorksFor(career: LocalizedCareer): object {\n const out: Record<string, unknown> = {};\n out['@type'] = 'Organization';\n out.name = career.organization;\n if (career.url !== undefined) out.url = career.url;\n return out;\n}\n\nfunction buildPastRoles(past: LocalizedCareer[]): object[] {\n return past.map((c) => {\n const out: Record<string, unknown> = {};\n out['@type'] = 'WorkRole';\n out.name = c.role;\n out.memberOf = { '@type': 'Organization', name: c.organization };\n out.startDate = c.startDate;\n // `null` denotes an unbounded position; omit so the published JSON-LD\n // does not carry an explicit `null`.\n if (c.endDate !== undefined && c.endDate !== null) out.endDate = c.endDate;\n return out;\n });\n}\n\nfunction buildProjects(projects: LocalizedProject[]): object[] {\n return projects.map((p) => {\n const out: Record<string, unknown> = {};\n out['@type'] = 'CreativeWork';\n out.name = p.title;\n if (p.url !== undefined) out.url = p.url;\n if (p.startDate !== undefined) out.datePublished = p.startDate;\n if (p.tags !== undefined && p.tags.length > 0) out.about = p.tags;\n return out;\n });\n}\n\nfunction buildSameAs(links: LocalizedLink[]): string[] | undefined {\n const out = links.filter((l) => SAMEAS_IDENTITY_TYPES.has(l.type)).map((l) => l.url);\n return out.length === 0 ? undefined : out;\n}\n\nfunction buildKnowsAbout(skills: Skill[]): string[] | undefined {\n if (skills.length === 0) return undefined;\n return skills.map((s) => s.label);\n}\n\nfunction buildEmail(contact: Contact): string | undefined {\n if (contact.showEmail !== true) return undefined;\n if (typeof contact.email !== 'string' || contact.email.length === 0) return undefined;\n return contact.email;\n}\n\nfunction buildKnowsLanguage(languages: LocalizedLanguage[]): string[] | undefined {\n if (languages.length === 0) return undefined;\n return languages.map((l) => l.language);\n}\n\nfunction buildCredentials(certifications: LocalizedCertification[]): object[] | undefined {\n if (certifications.length === 0) return undefined;\n return certifications.map((c) => {\n const out: Record<string, unknown> = {};\n out['@type'] = 'EducationalOccupationalCredential';\n if (c.title !== '') out.name = c.title;\n out.credentialCategory = 'certification';\n if (c.issuingOrganization !== '') {\n out.recognizedBy = {\n '@type': 'Organization',\n name: c.issuingOrganization,\n };\n }\n out.dateCreated = c.issueDate;\n if (c.expirationDate !== undefined && c.expirationDate !== null) {\n out.expires = c.expirationDate;\n }\n if (c.credentialId !== undefined) out.identifier = c.credentialId;\n if (c.url !== undefined) out.url = c.url;\n return out;\n });\n}\n\nfunction buildMemberOf(memberships: LocalizedMembership[]): object[] | undefined {\n if (memberships.length === 0) return undefined;\n // Schema.org Role wrapper pattern: the outer OrganizationRole\n // carries the role/date metadata; the inner `memberOf` Organization names the\n // body itself.\n return memberships.map((m) => {\n const out: Record<string, unknown> = {};\n out['@type'] = 'OrganizationRole';\n if (m.role !== undefined) out.roleName = m.role;\n out.startDate = m.startDate;\n if (m.endDate !== undefined && m.endDate !== null) out.endDate = m.endDate;\n if (m.description !== undefined) out.description = m.description;\n const org: Record<string, unknown> = { '@type': 'Organization', name: m.organization };\n if (m.url !== undefined) org.url = m.url;\n out.memberOf = org;\n return out;\n });\n}\n\nfunction buildAlumniOf(education: LocalizedEducation[]): object[] | undefined {\n if (education.length === 0) return undefined;\n // Schema.org Role wrapper pattern: outer OrganizationRole carries date +\n // concatenated degree/fieldOfStudy as roleName; inner `alumniOf` names\n // the EducationalOrganization.\n return education.map((e) => {\n const out: Record<string, unknown> = {};\n out['@type'] = 'OrganizationRole';\n const roleName = composeRoleName(e.degree, e.fieldOfStudy);\n if (roleName !== undefined) out.roleName = roleName;\n out.startDate = e.startDate;\n if (e.endDate !== undefined && e.endDate !== null) out.endDate = e.endDate;\n const description = composeEducationDescription(e.description, e.grade);\n if (description !== undefined) out.description = description;\n const org: Record<string, unknown> = {\n '@type': 'EducationalOrganization',\n name: e.institution,\n };\n if (e.url !== undefined) org.url = e.url;\n out.alumniOf = org;\n return out;\n });\n}\n\nfunction composeRoleName(\n degree: string | undefined,\n fieldOfStudy: string | undefined,\n): string | undefined {\n if (degree === undefined && fieldOfStudy === undefined) return undefined;\n if (degree !== undefined && fieldOfStudy !== undefined) return `${degree} (${fieldOfStudy})`;\n return degree ?? fieldOfStudy;\n}\n\nfunction composeEducationDescription(\n description: string | undefined,\n grade: string | undefined,\n): string | undefined {\n // `grade` may have already been stripped by the API privacy filter; if it\n // reaches us, prepend a labelled line to the description.\n if (grade !== undefined && description !== undefined) return `Grade: ${grade}. ${description}`;\n if (grade !== undefined) return `Grade: ${grade}`;\n return description;\n}\n\nfunction buildAwards(honors: LocalizedHonor[]): string[] | undefined {\n if (honors.length === 0) return undefined;\n return honors.map((h) => `${h.title} (${h.issuer}, ${h.date})`);\n}\n\nfunction buildVolunteeringRoles(volunteering: LocalizedVolunteering[]): object[] {\n return volunteering.map((v) => {\n const out: Record<string, unknown> = {};\n // Schema.org `VolunteerRole` is a pending property; we use the stable\n // `Role` type with `roleName` so indexers without VolunteerRole support\n // still read meaningful data.\n out['@type'] = 'Role';\n out.roleName = v.role;\n out.startDate = v.startDate;\n if (v.endDate !== undefined && v.endDate !== null) out.endDate = v.endDate;\n const description = composeVolunteeringDescription(v.cause, v.description);\n if (description !== undefined) out.description = description;\n const org: Record<string, unknown> = { '@type': 'Organization', name: v.organization };\n if (v.url !== undefined) org.url = v.url;\n out.memberOf = org;\n return out;\n });\n}\n\nfunction composeVolunteeringDescription(\n cause: string | undefined,\n description: string | undefined,\n): string | undefined {\n if (cause !== undefined && description !== undefined) return `Cause: ${cause}. ${description}`;\n if (cause !== undefined) return `Cause: ${cause}`;\n return description;\n}\n\nfunction buildPublications(publications: LocalizedPublication[]): object[] {\n return publications.map((p) => {\n const out: Record<string, unknown> = {};\n out['@type'] = 'ScholarlyArticle';\n out.name = p.title;\n if (p.publisher !== undefined) {\n out.publisher = { '@type': 'Organization', name: p.publisher };\n }\n out.datePublished = p.date;\n if (p.url !== undefined) out.url = p.url;\n if (p.doi !== undefined) {\n out.identifier = { '@type': 'PropertyValue', propertyID: 'DOI', value: p.doi };\n }\n if (p.coAuthors !== undefined && p.coAuthors.length > 0) {\n out.author = p.coAuthors.map((name) => ({ '@type': 'Person', name }));\n }\n return out;\n });\n}\n\nfunction buildCourses(courses: LocalizedCourse[]): object[] {\n return courses.map((c) => {\n const out: Record<string, unknown> = {};\n out['@type'] = 'Course';\n out.name = c.title;\n if (c.provider !== undefined) {\n out.provider = { '@type': 'Organization', name: c.provider };\n }\n if (c.courseNumber !== undefined) out.courseCode = c.courseNumber;\n if (c.certificateUrl !== undefined) out.url = c.certificateUrl;\n if (c.completionDate !== undefined) {\n // Schema.org Course has no direct date property; dates live on\n // CourseInstance via hasCourseInstance.\n out.hasCourseInstance = {\n '@type': 'CourseInstance',\n endDate: c.completionDate,\n };\n }\n return out;\n });\n}\n\nfunction buildPatentWorks(patents: LocalizedPatent[]): object[] {\n return patents.map((p) => {\n const out: Record<string, unknown> = {};\n // Schema.org Patent is not in the released vocabulary; emit CreativeWork\n // with additionalType pointing at the pending Patent URL so consumers\n // that recognize it can specialize, while others fall back gracefully.\n out['@type'] = 'CreativeWork';\n out.additionalType = 'https://schema.org/Patent';\n out.name = p.title;\n out.identifier = p.patentNumber;\n if (p.office !== undefined) {\n out.publisher = { '@type': 'Organization', name: p.office };\n }\n out.creativeWorkStatus = p.status;\n if (p.grantDate !== undefined) {\n out.datePublished = p.grantDate;\n } else if (p.filingDate !== undefined) {\n out.dateCreated = p.filingDate;\n }\n if (p.url !== undefined) out.url = p.url;\n if (p.coInventors !== undefined && p.coInventors.length > 0) {\n out.author = p.coInventors.map((name) => ({ '@type': 'Person', name }));\n }\n return out;\n });\n}\n","/**\n * Export and import for takuhon profile documents.\n *\n * {@link exportTakuhon} serialises a {@link Takuhon} document into a transport\n * form ({@link ExportedTakuhon}) that can be persisted to a file, an API\n * response, or any other byte-oriented sink. {@link importTakuhon} is the\n * inverse: it validates the input and returns a {@link Takuhon}.\n *\n * Scope of these helpers (deliberately narrow):\n * - Pure, in-memory data transforms — no I/O, no storage adapter coupling.\n * - {@link importTakuhon} **does not** auto-migrate older `schemaVersion`\n * values. Cross-version handling belongs to the CLI / API layer, which\n * composes `importTakuhon` + {@link migrateTakuhon} + storage adapters as\n * spelled out in operational-lifecycle §5.3.\n * - Round-trip equivalence (operational-lifecycle §5.1) is preserved up to\n * the documented `meta.updatedAt` exception.\n *\n * Asset embedding (Base64) and backup creation are out of scope here; both\n * are the storage / API layer's responsibility.\n */\n\nimport type { Takuhon } from './types.js';\nimport { validate, type ValidationError } from './validate.js';\n\n/**\n * Structural alias of {@link Takuhon}: the transport form is the document\n * itself. A wrapping envelope (e.g. `{ format, version, data, hash }`) is\n * intentionally avoided in Phase 1 — adding one later would be a breaking\n * change to the `GET /api/admin/export` response shape and would require a major\n * version bump of `@takuhon/core`.\n */\nexport type ExportedTakuhon = Takuhon;\n\n/** Options for {@link exportTakuhon}. */\nexport interface ExportOptions {\n /**\n * When `true` (default), `meta.updatedAt` is overwritten with the current\n * ISO-8601 timestamp. Set to `false` for byte-for-byte reproducible\n * exports (e.g. roundtrip tests).\n *\n * Round-trip equivalence per operational-lifecycle §5.1 explicitly lists\n * `meta.updatedAt` as the allowed exception.\n */\n updateTimestamp?: boolean;\n}\n\n/**\n * Thrown by {@link importTakuhon} when the input fails schema validation\n * (including an unsupported `schemaVersion`). The `errors` field carries\n * the same {@link ValidationError} list that `validate()` would have\n * returned, so the API layer can map them onto RFC 7807.\n */\nexport class ImportError extends Error {\n readonly errors?: ValidationError[];\n\n constructor(message: string, options?: { cause?: unknown; errors?: ValidationError[] }) {\n super(message, { cause: options?.cause });\n this.name = 'ImportError';\n this.errors = options?.errors;\n }\n}\n\n/**\n * Serialise a {@link Takuhon} into its transport form. The input is\n * deep-cloned via `JSON.parse(JSON.stringify(...))`; the original is never\n * mutated.\n */\nexport function exportTakuhon(data: Takuhon, options: ExportOptions = {}): ExportedTakuhon {\n const out = JSON.parse(JSON.stringify(data)) as ExportedTakuhon;\n if (options.updateTimestamp !== false) {\n out.meta = { ...out.meta, updatedAt: new Date().toISOString() };\n }\n return out;\n}\n\n/**\n * Validate an {@link ExportedTakuhon} and return it as a {@link Takuhon}.\n *\n * On schema validation failure (including an unsupported `schemaVersion`)\n * throws an {@link ImportError} with the structured `errors` attached. The\n * input is not mutated. The return value is a deep clone, so subsequent\n * caller mutations cannot reach back into the supplied document.\n *\n * Cross-version inputs (older `schemaVersion`) are out of scope: callers\n * (CLI / API layer) should run {@link migrateTakuhon} before calling this.\n */\nexport function importTakuhon(data: ExportedTakuhon): Takuhon {\n const result = validate(data);\n if (!result.ok) {\n throw new ImportError('imported document failed schema validation', { errors: result.errors });\n }\n return JSON.parse(JSON.stringify(result.data)) as Takuhon;\n}\n","/**\n * Module-private chain-building helper for the migration registry.\n *\n * Not re-exported from `@takuhon/core`'s public surface: the algorithm is an\n * implementation detail of {@link migrateTakuhon}, and adding it to the\n * public API would freeze its signature under semver. Unit tests import\n * this file directly to exercise the chain logic against synthetic\n * fixtures.\n */\n\nimport type { Takuhon } from '../types.js';\n\nimport type { Migration } from './index.js';\n\n/**\n * Build a forward chain of migrations from `from` to `to`. Returns `[]`\n * when `from === to`, or `null` when no chain exists or a cycle is\n * encountered. The walk is linear (one outgoing edge per `from`); a\n * visited-set guards against cycles introduced by misconfigured registries.\n */\nexport function findMigrationChain(\n from: string,\n to: string,\n registry: readonly Migration<Takuhon, Takuhon>[],\n): Migration<Takuhon, Takuhon>[] | null {\n if (from === to) return [];\n const byFrom = new Map<string, Migration<Takuhon, Takuhon>>();\n for (const m of registry) byFrom.set(m.from, m);\n const chain: Migration<Takuhon, Takuhon>[] = [];\n const visited = new Set<string>([from]);\n let cur = from;\n while (cur !== to) {\n const next = byFrom.get(cur);\n if (!next) return null;\n if (visited.has(next.to)) return null;\n chain.push(next);\n visited.add(next.to);\n cur = next.to;\n }\n return chain;\n}\n","/**\n * Forward migration from schema 0.1.0 to 0.2.0.\n *\n * Adds nine new top-level array fields (`certifications` / `memberships` /\n * `volunteering` / `honors` / `education` / `publications` / `languages` /\n * `courses` / `patents`) and the `meta.privacy` opt-out block. The\n * transformation is additive: existing fields pass through untouched and no\n * 0.1.x value is dropped.\n *\n * Conditional spread is intentional. The 0.1.x schema closes the document\n * root (`additionalProperties: false`), so a validated 0.1.x profile cannot\n * carry pre-existing values at the new keys. The migration nevertheless\n * runs on `unknown`-shaped input that may not have been validated yet — a\n * stored profile authored ahead of time with forward-compatible 0.2.0 keys,\n * an import file from a downstream consumer, etc. Preserving any value\n * already present at these keys prevents data loss in those paths.\n */\n\nimport type { Takuhon } from '../types.js';\n\nimport type { Migration } from './index.js';\n\nexport const v0_1_0_to_v0_2_0: Migration<Takuhon, Takuhon> = {\n from: '0.1.0',\n to: '0.2.0',\n migrate(data: Takuhon): Takuhon {\n const partial = data as Partial<Takuhon>;\n return {\n ...data,\n schemaVersion: '0.2.0',\n certifications: partial.certifications ?? [],\n memberships: partial.memberships ?? [],\n volunteering: partial.volunteering ?? [],\n honors: partial.honors ?? [],\n education: partial.education ?? [],\n publications: partial.publications ?? [],\n languages: partial.languages ?? [],\n courses: partial.courses ?? [],\n patents: partial.patents ?? [],\n };\n },\n};\n","/**\n * Forward migration from schema 0.2.0 to 0.3.0.\n *\n * Adds the `testScores` top-level array (standardized test / exam scores,\n * LinkedIn `Test_Scores.csv` equivalent). The transformation is additive:\n * existing fields pass through untouched and no 0.2.x value is dropped.\n *\n * Conditional spread mirrors `v0.1.0-to-v0.2.0`. The 0.2.x schema closes the\n * document root (`additionalProperties: false`), so a validated 0.2.x profile\n * cannot carry a pre-existing `testScores` value. The migration nevertheless\n * runs on `unknown`-shaped input that may not have been validated yet — a\n * stored profile authored ahead of time with a forward-compatible 0.3.0 key,\n * an import file from a downstream consumer, etc. Preserving any value already\n * present at `testScores` prevents data loss in those paths.\n */\n\nimport type { Takuhon } from '../types.js';\n\nimport type { Migration } from './index.js';\n\nexport const v0_2_0_to_v0_3_0: Migration<Takuhon, Takuhon> = {\n from: '0.2.0',\n to: '0.3.0',\n migrate(data: Takuhon): Takuhon {\n const partial = data as Partial<Takuhon>;\n return {\n ...data,\n schemaVersion: '0.3.0',\n testScores: partial.testScores ?? [],\n };\n },\n};\n","/**\n * Forward migration from schema 0.3.0 to 0.4.0.\n *\n * Adds the `recommendations` top-level array (owner-curated testimonials, the\n * LinkedIn `Recommendations_Received.csv` equivalent). The transformation is\n * additive: existing fields pass through untouched and no 0.3.x value is\n * dropped.\n *\n * Conditional spread mirrors the earlier migrations. The 0.3.x schema closes\n * the document root (`additionalProperties: false`), so a validated 0.3.x\n * profile cannot carry a pre-existing `recommendations` value. The migration\n * nevertheless runs on `unknown`-shaped input that may not have been validated\n * yet — a stored profile authored ahead of time with a forward-compatible\n * 0.4.0 key, an import file from a downstream consumer, etc. Preserving any\n * value already present at `recommendations` prevents data loss in those paths.\n */\n\nimport type { Takuhon } from '../types.js';\n\nimport type { Migration } from './index.js';\n\nexport const v0_3_0_to_v0_4_0: Migration<Takuhon, Takuhon> = {\n from: '0.3.0',\n to: '0.4.0',\n migrate(data: Takuhon): Takuhon {\n const partial = data as Partial<Takuhon>;\n return {\n ...data,\n schemaVersion: '0.4.0',\n recommendations: partial.recommendations ?? [],\n };\n },\n};\n","/**\n * Forward migration registry for `@takuhon/core`.\n *\n * Each migration is a pure function from a takuhon document at version `from`\n * to one at version `to`. The registry is consulted by {@link migrateTakuhon}\n * to build a chain when the requested target is more than one step away\n * (`0.1.0 → 0.3.0` is composed of `0.1.0→0.2.0` and `0.2.0→0.3.0`).\n *\n * Authoring conventions:\n * - File name: `vX.Y.Z-to-vA.B.C.ts`\n * - Pure function: must not mutate input, must not perform I/O\n * - Forward only: downgrades are not provided; recovery is via the backup\n * restore path (operational-lifecycle §4)\n * - Each entry ships with a unit test: sample input/output, idempotency\n * when applicable, and schema-pass against the target version's schema\n *\n * The chain-building algorithm lives in `_chain.ts` and is intentionally\n * not re-exported from `@takuhon/core` — it is an implementation detail of\n * {@link migrateTakuhon}.\n */\n\nimport type { Takuhon } from '../types.js';\n\nimport { v0_1_0_to_v0_2_0 } from './v0.1.0-to-v0.2.0.js';\nimport { v0_2_0_to_v0_3_0 } from './v0.2.0-to-v0.3.0.js';\nimport { v0_3_0_to_v0_4_0 } from './v0.3.0-to-v0.4.0.js';\n\n/**\n * A forward migration entry. `from` and `to` are semver strings matching\n * the `schemaVersion` field of the input and output documents. `migrate`\n * is pure: it must not mutate `data`.\n */\nexport interface Migration<From, To> {\n from: string;\n to: string;\n migrate(data: From): To;\n}\n\n/**\n * Forward migrations bundled with this build of `@takuhon/core`.\n *\n * Entries are listed in the order they would chain for forward migration\n * (`0.1.0 → 0.2.0 → 0.3.0 → ...`). {@link migrateTakuhon} consults this\n * array to build the chain between a source `schemaVersion` and a target.\n */\nexport const migrations: readonly Migration<Takuhon, Takuhon>[] = [\n v0_1_0_to_v0_2_0,\n v0_2_0_to_v0_3_0,\n v0_3_0_to_v0_4_0,\n];\n","/**\n * Forward migration entry point for takuhon documents.\n *\n * {@link migrateTakuhon} composes a chain of {@link Migration} entries from\n * the registry (`./migrations`) and applies them in order. The registry\n * currently ships the `0.1.0 → 0.2.0`, `0.2.0 → 0.3.0`, and `0.3.0 → 0.4.0`\n * forward migrations; a request whose source has no chain to the target\n * throws {@link MigrationError}.\n *\n * Scope (deliberately narrow, mirroring `export.ts`):\n * - Pure data transform — no I/O, no backup creation, no storage write.\n * - Backup-before-migrate (operational-lifecycle §3.1) is the storage /\n * API layer's responsibility; this function only transforms the\n * in-memory document.\n * - Forward only (operational-lifecycle §2.4); downgrade is via restore.\n */\n\nimport { findMigrationChain } from './migrations/_chain.js';\nimport { migrations } from './migrations/index.js';\nimport type { Takuhon } from './types.js';\n\n/**\n * Thrown by {@link migrateTakuhon} when no forward chain connects the\n * source `schemaVersion` to `targetVersion`. The message includes both\n * versions so the API layer can surface an actionable RFC 7807 problem.\n */\nexport class MigrationError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = 'MigrationError';\n }\n}\n\n/**\n * Migrate a takuhon document forward to `targetVersion`. Returns a deep\n * clone; the input is never mutated, even when a migration throws.\n *\n * @throws {MigrationError} when no forward chain exists from\n * `data.schemaVersion` to `targetVersion`.\n */\nexport function migrateTakuhon(data: Takuhon, targetVersion: string): Takuhon {\n const sourceVersion = data.schemaVersion;\n if (sourceVersion === targetVersion) {\n return JSON.parse(JSON.stringify(data)) as Takuhon;\n }\n const chain = findMigrationChain(sourceVersion, targetVersion, migrations);\n if (!chain) {\n throw new MigrationError(`No migration path from ${sourceVersion} to ${targetVersion}`);\n }\n let current: Takuhon = JSON.parse(JSON.stringify(data)) as Takuhon;\n for (const step of chain) {\n current = step.migrate(current);\n }\n return current;\n}\n","/**\n * Persistence contracts for takuhon profile documents and binary assets.\n *\n * Adapters (KV / R2 / filesystem / SQLite / …) implement these interfaces to\n * plug into `@takuhon/api`. All methods are async; failures surface as\n * exceptions in the {@link StorageError} family so the API layer can map them\n * onto RFC 7807 problem details.\n *\n * Design notes:\n * - `version` is an opaque ETag-like token (UUID, hash, monotonic counter —\n * the adapter chooses). It powers HTTP `If-Match` style optimistic locking\n * and is unrelated to {@link Takuhon.schemaVersion}, which describes the\n * document's data-model version.\n * - `getProfile()` returns a raw {@link Takuhon}, not a normalized or\n * locale-resolved one. Normalization and locale resolution belong to the\n * API / render layer; storage only persists.\n * - `saveProfile(data, ifMatch?)` rejects with {@link ConflictError} when\n * `ifMatch` is supplied and does not equal the current stored version.\n * When `ifMatch` is omitted, the adapter's policy decides whether to\n * overwrite unconditionally; per-implementation docs spell this out.\n * - `TakuhonAssetStorage` is intentionally a separate interface so deployments\n * that don't host user-uploaded media (e.g. static export) can omit it.\n * - The naming standardises on the lowercase \"Takuhon\" word (cf.\n * {@link Takuhon}, {@link LocalizedTakuhon}, `normalize`, `validate`) even\n * where upstream documents write \"Takuhon\".\n */\n\nimport type { Takuhon } from './types.js';\n\n/**\n * Persistence contract for the single profile document of a takuhon instance.\n *\n * Implementations: Cloudflare KV (Phase 3), filesystem (Phase 3+), in-memory\n * test doubles, and future SQL adapters.\n */\nexport interface TakuhonStorage {\n /**\n * Read the current profile document and its opaque version token.\n *\n * @throws {NotFoundError} when no profile has been saved yet.\n */\n getProfile(): Promise<{ data: Takuhon; version: string }>;\n\n /**\n * Replace the profile document. The returned `version` is the new opaque\n * token to supply as the next `ifMatch`.\n *\n * @param data the document to persist (raw, not normalized)\n * @param ifMatch when set, the adapter rejects the write unless the\n * current stored version equals this token\n * @throws {ConflictError} when `ifMatch` is supplied and does not equal\n * the current stored version\n */\n saveProfile(data: Takuhon, ifMatch?: string): Promise<{ version: string }>;\n\n /**\n * Remove the profile document. Idempotent: no error when nothing is stored.\n */\n deleteProfile(): Promise<void>;\n}\n\n/**\n * Metadata for a stored binary asset, returned by {@link TakuhonAssetStorage}.\n *\n * `url` is the relative path used inside the document (`/assets/...`);\n * `publicUrl` is the absolute URL a browser can fetch. The two are kept\n * distinct because adapters may serve assets from a different host than the\n * profile (e.g. Cloudflare R2 + custom CDN).\n */\nexport interface AssetRecord {\n id: string;\n url: string;\n publicUrl: string;\n mimeType: string;\n size: number;\n width?: number;\n height?: number;\n /** ISO-8601 timestamp. */\n createdAt?: string;\n}\n\n/**\n * Caller hints for {@link TakuhonAssetStorage.putAsset}. Both fields are\n * optional; when omitted, the adapter falls back to the `File` / `Blob`\n * metadata. Adapters are responsible for magic-byte verification, EXIF\n * stripping, and dimension limits — callers must not pre-process.\n */\nexport interface AssetOptions {\n filename?: string;\n contentType?: string;\n}\n\n/**\n * Persistence contract for binary assets (avatars, project images, …).\n *\n * `listAssets()` is unbounded by design for the MVP; later phases may\n * introduce paginated semantics with a different return shape. `getPublicUrl()`\n * takes only an `assetId` today; a future options object (e.g. `expiresIn`\n * for signed URLs) would be added in a backward-compatible way.\n */\nexport interface TakuhonAssetStorage {\n putAsset(file: File | Blob, options?: AssetOptions): Promise<AssetRecord>;\n /** @throws {NotFoundError} when no asset exists for `assetId`. */\n getPublicUrl(assetId: string): Promise<string>;\n /** Idempotent: no error when the asset is already absent. */\n deleteAsset(assetId: string): Promise<void>;\n listAssets(): Promise<AssetRecord[]>;\n}\n\n/**\n * Base class for errors thrown by storage adapters. Catch this to handle\n * any storage-layer failure uniformly; check `instanceof` of a subclass\n * (e.g. {@link NotFoundError}, {@link ConflictError}) to discriminate.\n */\nexport class StorageError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = 'StorageError';\n }\n}\n\n/** Thrown when a requested resource (profile or asset) does not exist. */\nexport class NotFoundError extends StorageError {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = 'NotFoundError';\n }\n}\n\n/**\n * Thrown when an optimistic-locking precondition fails: the caller supplied\n * an `ifMatch` token that does not equal the current stored version.\n *\n * `currentVersion` (when set) carries the actual current version so the\n * caller can decide between refetch-and-retry and surfacing a 409 to the\n * end user without an extra round trip.\n */\nexport class ConflictError extends StorageError {\n readonly currentVersion?: string;\n\n constructor(message: string, options?: { currentVersion?: string; cause?: unknown }) {\n super(message, { cause: options?.cause });\n this.name = 'ConflictError';\n this.currentVersion = options?.currentVersion;\n }\n}\n","/**\n * @takuhon/core — canonical JSON Schema, hand-written TypeScript types,\n * Ajv-backed validation, document normalization, and locale resolution for\n * takuhon profile data.\n *\n * Public surface (Phase 1):\n * - {@link schema}: the JSON Schema 2020-12 contract bundled with this build.\n * - {@link SCHEMA_VERSION}: the version of that schema (matches the `$id`).\n * - {@link validate} / {@link ValidationResult} / {@link ValidationError} /\n * {@link SUPPORTED_SCHEMA_VERSIONS}: Result-style validator backed by Ajv.\n * - {@link normalize} / {@link NormalizedTakuhon}: canonicalize a validated\n * document (sort lists by `order`, drop blank localized entries).\n * - {@link resolveLocale} / {@link LocalizedTakuhon}: collapse a multi-locale\n * document to a single requested locale with BCP-47 regional fallback.\n * - {@link generateJsonLd} / {@link generatePersonJsonLd} /\n * {@link generateProfilePageJsonLd}: emit Schema.org JSON-LD\n * (`ProfilePage` wrapping `Person`) from a locale-resolved document.\n * - {@link TakuhonStorage} / {@link TakuhonAssetStorage}: persistence contracts\n * for adapters (KV / R2 / filesystem / SQLite / …), with the\n * {@link StorageError} / {@link NotFoundError} / {@link ConflictError}\n * exception family for optimistic-locking and not-found signalling.\n * - {@link exportTakuhon} / {@link importTakuhon} / {@link ExportOptions} /\n * {@link ExportedTakuhon} / {@link ImportError}: roundtrip-stable\n * serialisation for transport (file, API response, …).\n * - {@link migrateTakuhon} / {@link Migration} / {@link migrations} /\n * {@link MigrationError}: forward-only migration registry, chaining\n * `0.1.0 → 0.2.0 → 0.3.0 → 0.4.0`.\n * - Domain types: {@link Takuhon} and its constituent shapes (`Profile`,\n * `Settings`, `Career`, `Project`, `Link` discriminated union, etc.).\n */\n\nexport { schema } from './schema.js';\nexport type { Schema } from './schema.js';\n\nexport { SUPPORTED_SCHEMA_VERSIONS, validate } from './validate.js';\nexport type { ValidationError, ValidationResult } from './validate.js';\n\nexport { normalize } from './normalize.js';\nexport { resolveLocale } from './resolve-locale.js';\nexport { generateJsonLd, generatePersonJsonLd, generateProfilePageJsonLd } from './jsonld.js';\n\nexport { ImportError, exportTakuhon, importTakuhon } from './export.js';\nexport type { ExportOptions, ExportedTakuhon } from './export.js';\n\nexport { MigrationError, migrateTakuhon } from './migrate.js';\nexport { migrations } from './migrations/index.js';\nexport type { Migration } from './migrations/index.js';\n\nexport { ConflictError, NotFoundError, StorageError } from './storage-interface.js';\nexport type {\n AssetOptions,\n AssetRecord,\n TakuhonAssetStorage,\n TakuhonStorage,\n} from './storage-interface.js';\n\nexport type {\n Address,\n Avatar,\n Career,\n Certification,\n Contact,\n ContentLicense,\n ContentLicenseAttribution,\n Course,\n Education,\n Honor,\n Iso3166Alpha2,\n IsoDateTime,\n Language,\n LanguageProficiency,\n Link,\n LinkBuiltin,\n LinkCustom,\n LinkType,\n LocaleTag,\n LocalizedAddress,\n LocalizedAvatar,\n LocalizedBody,\n LocalizedCareer,\n LocalizedCertification,\n LocalizedCourse,\n LocalizedEducation,\n LocalizedHonor,\n LocalizedLanguage,\n LocalizedLink,\n LocalizedLinkBuiltin,\n LocalizedLinkCustom,\n LocalizedMembership,\n LocalizedPatent,\n LocalizedProfile,\n LocalizedProject,\n LocalizedPublication,\n LocalizedRecommendation,\n LocalizedRecommendationAuthor,\n LocalizedTakuhon,\n LocalizedTestScore,\n LocalizedTitle,\n LocalizedVolunteering,\n Membership,\n Meta,\n MetaPrivacy,\n NormalizedTakuhon,\n Patent,\n PatentStatus,\n Profile,\n Project,\n Publication,\n Recommendation,\n RecommendationAuthor,\n Settings,\n Skill,\n Slug,\n Takuhon,\n TestScore,\n Volunteering,\n YearMonth,\n} from './types.js';\n\n/**\n * Version of the takuhon schema bundled with this build of `@takuhon/core`.\n * A takuhon profile document's `schemaVersion` field must be migrate-compatible\n * with this version. See operational-lifecycle docs for the migration policy.\n */\nexport const SCHEMA_VERSION = '0.4.0';\n"],"mappings":"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","names":["out"]}
1
+ {"version":3,"sources":["../takuhon.schema.json","../src/schema.ts","../src/validate.ts","../src/normalize.ts","../src/locale-tag.ts","../src/resolve-locale.ts","../src/jsonld.ts","../src/export.ts","../src/privacy-filter.ts","../src/migrations/_chain.ts","../src/migrations/v0.1.0-to-v0.2.0.ts","../src/migrations/v0.2.0-to-v0.3.0.ts","../src/migrations/v0.3.0-to-v0.4.0.ts","../src/migrations/index.ts","../src/migrate.ts","../src/storage-interface.ts","../src/index.ts"],"sourcesContent":["{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://takuhon.example/schemas/0.4.0/takuhon.schema.json\",\n \"title\": \"Takuhon Profile\",\n \"description\": \"Portable profile data format consumed by @takuhon/core. The canonical contract for profile content authored as takuhon.json.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"schemaVersion\",\n \"profile\",\n \"links\",\n \"careers\",\n \"projects\",\n \"skills\",\n \"contact\",\n \"settings\",\n \"meta\"\n ],\n \"properties\": {\n \"schemaVersion\": {\n \"type\": \"string\",\n \"pattern\": \"^[0-9]+\\\\.[0-9]+\\\\.[0-9]+(-[a-zA-Z0-9.-]+)?$\",\n \"description\": \"Semantic version of the takuhon schema this document conforms to.\"\n },\n \"profile\": { \"$ref\": \"#/$defs/Profile\" },\n \"links\": {\n \"type\": \"array\",\n \"maxItems\": 100,\n \"items\": { \"$ref\": \"#/$defs/Link\" }\n },\n \"careers\": {\n \"type\": \"array\",\n \"maxItems\": 50,\n \"items\": { \"$ref\": \"#/$defs/Career\" }\n },\n \"projects\": {\n \"type\": \"array\",\n \"maxItems\": 100,\n \"items\": { \"$ref\": \"#/$defs/Project\" }\n },\n \"skills\": {\n \"type\": \"array\",\n \"maxItems\": 200,\n \"items\": { \"$ref\": \"#/$defs/Skill\" }\n },\n \"certifications\": {\n \"type\": \"array\",\n \"maxItems\": 50,\n \"items\": { \"$ref\": \"#/$defs/Certification\" }\n },\n \"memberships\": {\n \"type\": \"array\",\n \"maxItems\": 50,\n \"items\": { \"$ref\": \"#/$defs/Membership\" }\n },\n \"volunteering\": {\n \"type\": \"array\",\n \"maxItems\": 50,\n \"items\": { \"$ref\": \"#/$defs/Volunteering\" }\n },\n \"honors\": {\n \"type\": \"array\",\n \"maxItems\": 50,\n \"items\": { \"$ref\": \"#/$defs/Honor\" }\n },\n \"education\": {\n \"type\": \"array\",\n \"maxItems\": 30,\n \"items\": { \"$ref\": \"#/$defs/Education\" }\n },\n \"publications\": {\n \"type\": \"array\",\n \"maxItems\": 100,\n \"items\": { \"$ref\": \"#/$defs/Publication\" }\n },\n \"languages\": {\n \"type\": \"array\",\n \"maxItems\": 30,\n \"items\": { \"$ref\": \"#/$defs/Language\" }\n },\n \"courses\": {\n \"type\": \"array\",\n \"maxItems\": 100,\n \"items\": { \"$ref\": \"#/$defs/Course\" }\n },\n \"patents\": {\n \"type\": \"array\",\n \"maxItems\": 50,\n \"items\": { \"$ref\": \"#/$defs/Patent\" }\n },\n \"testScores\": {\n \"type\": \"array\",\n \"maxItems\": 30,\n \"items\": { \"$ref\": \"#/$defs/TestScore\" }\n },\n \"recommendations\": {\n \"type\": \"array\",\n \"maxItems\": 50,\n \"items\": { \"$ref\": \"#/$defs/Recommendation\" }\n },\n \"contact\": { \"$ref\": \"#/$defs/Contact\" },\n \"settings\": { \"$ref\": \"#/$defs/Settings\" },\n \"meta\": { \"$ref\": \"#/$defs/Meta\" }\n },\n \"$defs\": {\n \"LocaleTag\": {\n \"type\": \"string\",\n \"minLength\": 2,\n \"maxLength\": 35,\n \"pattern\": \"^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})*$\",\n \"description\": \"BCP-47 language tag (e.g., 'en', 'ja', 'zh-Hant', 'pt-BR').\"\n },\n \"Iso3166Alpha2\": {\n \"type\": \"string\",\n \"pattern\": \"^[A-Z]{2}$\",\n \"description\": \"ISO 3166-1 alpha-2 country code (uppercase, two letters).\"\n },\n \"YearMonth\": {\n \"type\": \"string\",\n \"pattern\": \"^[0-9]{4}-(0[1-9]|1[0-2])$\",\n \"description\": \"Year-month in 'YYYY-MM' format (Gregorian calendar).\"\n },\n \"IsoDateTime\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"ISO 8601 date-time (e.g., 2026-05-11T12:34:56Z).\"\n },\n \"Url\": {\n \"type\": \"string\",\n \"format\": \"uri\",\n \"maxLength\": 2048\n },\n \"Email\": {\n \"type\": \"string\",\n \"format\": \"email\",\n \"maxLength\": 254\n },\n \"Slug\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 64,\n \"pattern\": \"^[a-z0-9][a-z0-9-]*$\",\n \"description\": \"URL-safe identifier (lowercase alphanumerics and hyphens, must start with alphanumeric).\"\n },\n \"LocalizedTitle\": {\n \"type\": \"object\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"type\": \"string\",\n \"pattern\": \"^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})*$\"\n },\n \"additionalProperties\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 200\n },\n \"description\": \"Map of BCP-47 locale tag to short title-like string (max 200 chars per value).\"\n },\n \"LocalizedBody\": {\n \"type\": \"object\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"type\": \"string\",\n \"pattern\": \"^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})*$\"\n },\n \"additionalProperties\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 5000\n },\n \"description\": \"Map of BCP-47 locale tag to body-length string (max 5000 chars per value).\"\n },\n \"LinkType\": {\n \"type\": \"string\",\n \"enum\": [\n \"website\",\n \"blog\",\n \"github\",\n \"gitlab\",\n \"linkedin\",\n \"x\",\n \"mastodon\",\n \"bluesky\",\n \"instagram\",\n \"youtube\",\n \"threads\",\n \"facebook\",\n \"email\",\n \"rss\",\n \"custom\"\n ],\n \"description\": \"Identifies the kind of link. 'custom' requires iconUrl.\"\n },\n \"Profile\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"displayName\"],\n \"properties\": {\n \"displayName\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"tagline\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"bio\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"avatar\": { \"$ref\": \"#/$defs/Avatar\" },\n \"location\": { \"$ref\": \"#/$defs/Address\" }\n }\n },\n \"Avatar\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"url\"],\n \"properties\": {\n \"url\": {\n \"type\": \"string\",\n \"format\": \"uri-reference\",\n \"maxLength\": 2048,\n \"description\": \"URL or path to the avatar image.\"\n },\n \"alt\": { \"$ref\": \"#/$defs/LocalizedTitle\" }\n }\n },\n \"Address\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"properties\": {\n \"country\": { \"$ref\": \"#/$defs/Iso3166Alpha2\" },\n \"region\": { \"type\": \"string\", \"maxLength\": 100 },\n \"locality\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"display\": { \"$ref\": \"#/$defs/LocalizedTitle\" }\n }\n },\n \"Link\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"id\", \"type\", \"url\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"type\": { \"$ref\": \"#/$defs/LinkType\" },\n \"label\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"featured\": { \"type\": \"boolean\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 },\n \"iconUrl\": { \"$ref\": \"#/$defs/Url\" }\n },\n \"allOf\": [\n {\n \"if\": {\n \"properties\": { \"type\": { \"const\": \"custom\" } },\n \"required\": [\"type\"]\n },\n \"then\": {\n \"properties\": { \"iconUrl\": { \"$ref\": \"#/$defs/Url\" } },\n \"required\": [\"iconUrl\"]\n }\n }\n ]\n },\n \"Career\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"organization\", \"role\", \"startDate\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"organization\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"role\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"startDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"endDate\": {\n \"anyOf\": [{ \"$ref\": \"#/$defs/YearMonth\" }, { \"type\": \"null\" }]\n },\n \"isCurrent\": { \"type\": \"boolean\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"location\": { \"$ref\": \"#/$defs/Address\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Project\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"title\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"title\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"tags\": {\n \"type\": \"array\",\n \"maxItems\": 30,\n \"items\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 50 }\n },\n \"relatedCareerId\": { \"$ref\": \"#/$defs/Slug\" },\n \"startDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"endDate\": {\n \"anyOf\": [{ \"$ref\": \"#/$defs/YearMonth\" }, { \"type\": \"null\" }]\n },\n \"highlighted\": { \"type\": \"boolean\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Skill\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"label\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"label\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 100 },\n \"category\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 64,\n \"description\": \"Recommended values (extensible): programming, design, business, communication, language, music, art, sports, other.\"\n },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Contact\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"properties\": {\n \"email\": { \"$ref\": \"#/$defs/Email\" },\n \"showEmail\": { \"type\": \"boolean\", \"default\": false },\n \"formUrl\": { \"$ref\": \"#/$defs/Url\" }\n }\n },\n \"Settings\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"defaultLocale\", \"availableLocales\"],\n \"properties\": {\n \"defaultLocale\": { \"$ref\": \"#/$defs/LocaleTag\" },\n \"fallbackLocale\": { \"$ref\": \"#/$defs/LocaleTag\" },\n \"availableLocales\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"maxItems\": 50,\n \"uniqueItems\": true,\n \"items\": { \"$ref\": \"#/$defs/LocaleTag\" }\n },\n \"theme\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 64,\n \"description\": \"UI theme identifier. 'default' is the built-in theme; adapters may add more.\"\n },\n \"showPoweredBy\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"Display the 'Powered by takuhon' attribution in the rendered profile.\"\n },\n \"enableJsonLd\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"Emit Schema.org JSON-LD on the rendered profile page.\"\n },\n \"enableApi\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"Expose the public read API endpoints (GET /api/profile, /api/jsonld, /api/schema, /takuhon.json).\"\n },\n \"enableAnalytics\": {\n \"type\": \"boolean\",\n \"default\": false,\n \"description\": \"Opt-in flag for first-party analytics. Default is false to keep takuhon privacy-respecting by default.\"\n }\n }\n },\n \"Meta\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"contentLicense\"],\n \"properties\": {\n \"createdAt\": { \"$ref\": \"#/$defs/IsoDateTime\" },\n \"updatedAt\": { \"$ref\": \"#/$defs/IsoDateTime\" },\n \"generator\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 100,\n \"description\": \"Tool that produced this document (e.g. 'Takuhon', 'create-takuhon@0.1.0').\"\n },\n \"contentLicense\": { \"$ref\": \"#/$defs/ContentLicense\" },\n \"privacy\": { \"$ref\": \"#/$defs/MetaPrivacy\" }\n }\n },\n \"ContentLicense\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"spdxId\"],\n \"properties\": {\n \"spdxId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 64,\n \"description\": \"SPDX identifier (e.g., 'CC-BY-4.0', 'CC0-1.0') or 'Proprietary'. No default; the profile owner must choose explicitly.\"\n },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"attribution\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"name\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 200 },\n \"url\": { \"$ref\": \"#/$defs/Url\" }\n }\n },\n \"rights\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 1000,\n \"description\": \"Free-form rights statement (used when spdxId='Proprietary' or for additional notices).\"\n }\n }\n },\n \"MetaPrivacy\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"description\": \"Opt-out flags that strip personally identifying fields from public API output (GET /api/profile, /api/jsonld, /takuhon.json). Admin endpoints (PUT /api/admin/*, GET /api/admin/export) ignore these flags. Privacy-by-default: omitting the object or individual flags is equivalent to true.\",\n \"properties\": {\n \"hideCredentialIds\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"When true (default), strip certifications[*].credentialId from public responses.\"\n },\n \"hideEducationGrades\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"When true (default), strip education[*].grade from public responses.\"\n }\n }\n },\n \"Certification\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"title\", \"issuingOrganization\", \"issueDate\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"title\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"issuingOrganization\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"issueDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"expirationDate\": {\n \"anyOf\": [{ \"$ref\": \"#/$defs/YearMonth\" }, { \"type\": \"null\" }],\n \"description\": \"null = explicitly 'no expiration'. Omit if unknown/unstated.\"\n },\n \"credentialId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 100,\n \"description\": \"License or certificate number. Public exposure controlled by meta.privacy.hideCredentialIds.\"\n },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Membership\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"organization\", \"startDate\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"organization\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"role\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"startDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"endDate\": {\n \"anyOf\": [{ \"$ref\": \"#/$defs/YearMonth\" }, { \"type\": \"null\" }],\n \"description\": \"null = ongoing. Omit if unknown.\"\n },\n \"isCurrent\": { \"type\": \"boolean\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Volunteering\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"organization\", \"role\", \"startDate\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"organization\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"role\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"cause\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"startDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"endDate\": {\n \"anyOf\": [{ \"$ref\": \"#/$defs/YearMonth\" }, { \"type\": \"null\" }]\n },\n \"isCurrent\": { \"type\": \"boolean\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Honor\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"title\", \"issuer\", \"date\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"title\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"issuer\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"date\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Education\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"institution\", \"startDate\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"institution\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"degree\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"fieldOfStudy\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"grade\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 50,\n \"description\": \"Free-form grade / class / GPA. Public exposure controlled by meta.privacy.hideEducationGrades.\"\n },\n \"startDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"endDate\": {\n \"anyOf\": [{ \"$ref\": \"#/$defs/YearMonth\" }, { \"type\": \"null\" }],\n \"description\": \"null = currently enrolled.\"\n },\n \"isCurrent\": { \"type\": \"boolean\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Publication\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"title\", \"date\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"title\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"publisher\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"date\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"doi\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 200,\n \"description\": \"DOI identifier (e.g. '10.1145/3548643.3548644'). The full URL goes in 'url'.\"\n },\n \"coAuthors\": {\n \"type\": \"array\",\n \"maxItems\": 50,\n \"items\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 100 },\n \"description\": \"Co-author names in original script. Excludes the profile owner.\"\n },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Language\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"language\", \"proficiency\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"language\": { \"$ref\": \"#/$defs/LocaleTag\" },\n \"displayName\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"proficiency\": {\n \"type\": \"string\",\n \"enum\": [\"native\", \"fluent\", \"professional\", \"intermediate\", \"basic\"],\n \"description\": \"LinkedIn-compatible 5-level proficiency.\"\n },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Course\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"title\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"title\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"provider\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"courseNumber\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 50 },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"completionDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"certificateUrl\": { \"$ref\": \"#/$defs/Url\" },\n \"relatedEducationId\": {\n \"$ref\": \"#/$defs/Slug\",\n \"description\": \"Optional reference to an education[].id (e.g. for university coursework).\"\n },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Patent\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"title\", \"patentNumber\", \"status\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"title\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"patentNumber\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 100 },\n \"office\": {\n \"type\": \"string\",\n \"maxLength\": 100,\n \"description\": \"Patent office name (e.g. 'USPTO', 'JPO', 'EPO').\"\n },\n \"status\": {\n \"type\": \"string\",\n \"enum\": [\"pending\", \"issued\", \"expired\", \"abandoned\"]\n },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"filingDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"grantDate\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"coInventors\": {\n \"type\": \"array\",\n \"maxItems\": 20,\n \"items\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 100 }\n },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"TestScore\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"title\", \"score\", \"date\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"title\": { \"$ref\": \"#/$defs/LocalizedTitle\" },\n \"score\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 50,\n \"description\": \"Free-form score string (e.g. '112 / 120', '330', 'N1 Pass', or a percentile). The validator does not interpret its contents.\"\n },\n \"date\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"relatedEducationId\": {\n \"$ref\": \"#/$defs/Slug\",\n \"description\": \"Optional reference to an education[].id (e.g. for a university course exam).\"\n },\n \"description\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"url\": { \"$ref\": \"#/$defs/Url\" },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"Recommendation\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"id\", \"body\", \"author\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/Slug\" },\n \"body\": { \"$ref\": \"#/$defs/LocalizedBody\" },\n \"author\": { \"$ref\": \"#/$defs/RecommendationAuthor\" },\n \"relationship\": {\n \"$ref\": \"#/$defs/LocalizedTitle\",\n \"description\": \"How the recommender relates to the profile owner (e.g. 'managed directly', 'worked together').\"\n },\n \"date\": { \"$ref\": \"#/$defs/YearMonth\" },\n \"relatedCareerId\": {\n \"$ref\": \"#/$defs/Slug\",\n \"description\": \"Optional reference to a careers[].id (the position the recommendation pertains to).\"\n },\n \"relatedEducationId\": {\n \"$ref\": \"#/$defs/Slug\",\n \"description\": \"Optional reference to an education[].id (e.g. a recommendation from a professor).\"\n },\n \"order\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n },\n \"RecommendationAuthor\": {\n \"type\": \"object\",\n \"additionalProperties\": true,\n \"required\": [\"name\"],\n \"properties\": {\n \"name\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 100,\n \"description\": \"Recommender's name, in its original script. Owner-curated; takuhon does not verify it.\"\n },\n \"headline\": {\n \"$ref\": \"#/$defs/LocalizedTitle\",\n \"description\": \"Recommender's title / role / organization at the time of the recommendation.\"\n },\n \"url\": {\n \"$ref\": \"#/$defs/Url\",\n \"description\": \"Link to the recommender's profile, for external verification by the reader.\"\n }\n }\n }\n }\n}\n","/**\n * Re-exports the canonical JSON Schema for takuhon profiles.\n *\n * The schema source of truth lives at `packages/core/takuhon.schema.json`\n * (also distributed via the `@takuhon/core/schema.json` sub-path). This module\n * is the convenient ESM-side entry point for consumers that want to feed it\n * directly to a JSON Schema validator (e.g. Ajv) without a filesystem read.\n */\n\nimport schemaJson from '../takuhon.schema.json' with { type: 'json' };\n\nexport const schema = schemaJson;\nexport type Schema = typeof schemaJson;\n","/**\n * Schema validation for takuhon profile documents.\n *\n * Compiles the canonical {@link import('../takuhon.schema.json')} once at module\n * load and exposes a Result-style {@link validate} that returns either the\n * narrowed {@link Takuhon} value or a list of structured {@link ValidationError}s.\n * The validator is the canonical correctness boundary inside `@takuhon/core`:\n * `normalize` (commit 3) and the API layer (commit 11+) both rely on this\n * function to know the shape they are working with.\n *\n * Design notes:\n * - Returns a discriminated union rather than throwing so callers (CLI,\n * normalize, RFC 7807 Problem Details adapters) can route errors however they\n * like without paying for stack capture on every failure.\n * - Errors carry the RFC 6901 JSON Pointer of the offending value plus the\n * failing Ajv keyword, so consumers can render messages or look up the\n * relevant Spec section without leaking Ajv-specific types.\n * - The Ajv 2020 build is used because the schema declares\n * `$schema: \"https://json-schema.org/draft/2020-12/schema\"`.\n */\n\nimport type { ErrorObject } from 'ajv';\nimport Ajv2020 from 'ajv/dist/2020.js';\nimport addFormats from 'ajv-formats';\n\nimport { schema } from './schema.js';\nimport type { Takuhon } from './types.js';\n\n/**\n * Schema versions this build of `@takuhon/core` accepts directly.\n *\n * The migration registry (Phase 1 commit 6+) will translate older `schemaVersion`\n * values into the current one before validation runs, so this list reflects the\n * versions whose JSON Schema this package literally bundles, not the full\n * support window seen by end users.\n */\nexport const SUPPORTED_SCHEMA_VERSIONS = ['0.1.0', '0.2.0', '0.3.0', '0.4.0'] as const;\n\n/**\n * A single validation failure.\n *\n * The shape is intentionally schema-agnostic: an API layer can adapt it into an\n * RFC 7807 Problem Details payload, a CLI can render the message, and a future\n * spec-section lookup table can join on {@link pointer} to surface\n * documentation references. A `specSection` field will be added in a later\n * commit; this minimal surface is what commit 2 ships.\n */\nexport interface ValidationError {\n /** RFC 6901 JSON Pointer to the offending value, e.g. `\"/links/4/iconUrl\"`. */\n pointer: string;\n /** Human-readable failure description (sourced from Ajv when available). */\n message: string;\n /**\n * The schema keyword that failed: `'required'`, `'enum'`, `'pattern'`,\n * `'additionalProperties'`, `'format'`, `'maxItems'`, `'maxLength'`, etc.\n * The value `'schemaVersion'` is reserved for documents whose\n * `schemaVersion` lies outside {@link SUPPORTED_SCHEMA_VERSIONS}.\n */\n keyword: string;\n /** JSON Pointer into the schema for the failing rule, e.g. `\"#/$defs/Link/required\"`. */\n schemaPointer?: string;\n}\n\n/** Result of {@link validate}. Narrow on `ok` to access `data` or `errors`. */\nexport type ValidationResult =\n | { ok: true; data: Takuhon }\n | { ok: false; errors: ValidationError[] };\n\nconst ajv = new Ajv2020({\n allErrors: true,\n strict: true,\n});\naddFormats(ajv);\n\n// Per design decision #5 we skip `JSONSchemaType<Takuhon>` and let Ajv compile\n// the schema object as-is; the `<Takuhon>` type argument only records the\n// validated result type for downstream narrowing.\nconst compiled = ajv.compile<Takuhon>(schema);\n\n/**\n * Validate an arbitrary value against the bundled takuhon schema.\n *\n * @param data unknown JSON-like value (typically parsed from a `takuhon.json` file)\n * @returns A discriminated result. On success `data` is narrowed to {@link Takuhon};\n * on failure `errors` is a non-empty list of {@link ValidationError}s.\n */\nexport function validate(data: unknown): ValidationResult {\n // Pre-Ajv gate: reject anything that is not a plain object so callers get a\n // clearer top-level error than Ajv's cascade of \"must be object\" / property\n // failures when handed an array, null, or a primitive.\n if (typeof data !== 'object' || data === null || Array.isArray(data)) {\n return {\n ok: false,\n errors: [\n {\n pointer: '',\n message: 'takuhon.json must be a JSON object.',\n keyword: 'type',\n },\n ],\n };\n }\n\n // Pre-Ajv gate: reject documents whose schemaVersion sits outside the\n // supported window with a dedicated keyword. Migration (commit 6+) will\n // translate older versions into the current one before reaching this point.\n const candidate = data as { schemaVersion?: unknown };\n if (typeof candidate.schemaVersion === 'string' && !isSupportedVersion(candidate.schemaVersion)) {\n return {\n ok: false,\n errors: [\n {\n pointer: '/schemaVersion',\n message: `schemaVersion \"${candidate.schemaVersion}\" is not in the supported window (${SUPPORTED_SCHEMA_VERSIONS.join(\n ', ',\n )}).`,\n keyword: 'schemaVersion',\n },\n ],\n };\n }\n\n if (compiled(data)) {\n // The schema marks several top-level arrays as optional for back-compat\n // (the nine added in 0.2.0, `testScores` in 0.3.0, and `recommendations`\n // in 0.4.0). The TypeScript `Takuhon` shape requires them so\n // downstream code never has to check for `undefined`. We clone the\n // caller's input before coercing so a successful validate() never\n // mutates the original — callers can keep referencing the value they\n // passed in. JS preserves insertion order, so new keys land at the end\n // of the cloned object; `normalize()` is responsible for canonical\n // field order.\n const cloned = JSON.parse(JSON.stringify(data)) as Takuhon;\n coerceMissingArrays(cloned);\n\n // Post-Ajv check: `languages[].language` uniqueness. JSON Schema\n // `uniqueItems` only catches whole-object duplicates and cannot enforce\n // by-key uniqueness, so we walk the array here and reject duplicates as\n // a synthetic ValidationError.\n const duplicate = findDuplicateLanguage(cloned.languages);\n if (duplicate !== undefined) {\n return {\n ok: false,\n errors: [\n {\n pointer: `/languages/${duplicate.index}/language`,\n message: `Duplicate languages[].language value \"${duplicate.tag}\" — each entry must declare a unique BCP-47 tag.`,\n keyword: 'uniqueItems',\n },\n ],\n };\n }\n\n return { ok: true, data: cloned };\n }\n\n return {\n ok: false,\n errors: (compiled.errors ?? []).map(toValidationError),\n };\n}\n\nconst COERCED_ARRAY_KEYS = [\n 'certifications',\n 'memberships',\n 'volunteering',\n 'honors',\n 'education',\n 'publications',\n 'languages',\n 'courses',\n 'patents',\n 'testScores',\n 'recommendations',\n] as const;\n\nfunction coerceMissingArrays(data: Takuhon): void {\n const bag = data as unknown as Record<string, unknown>;\n for (const key of COERCED_ARRAY_KEYS) {\n if (!Array.isArray(bag[key])) {\n bag[key] = [];\n }\n }\n}\n\nfunction findDuplicateLanguage(\n languages: Takuhon['languages'],\n): { index: number; tag: string } | undefined {\n const seen = new Map<string, number>();\n for (let i = 0; i < languages.length; i++) {\n const entry = languages[i];\n if (entry === undefined) continue;\n const key = entry.language.toLowerCase();\n if (seen.has(key)) return { index: i, tag: entry.language };\n seen.set(key, i);\n }\n return undefined;\n}\n\nfunction isSupportedVersion(value: string): boolean {\n return (SUPPORTED_SCHEMA_VERSIONS as readonly string[]).includes(value);\n}\n\nfunction toValidationError(err: ErrorObject): ValidationError {\n let pointer = err.instancePath;\n\n if (err.keyword === 'required') {\n const missing = (err.params as { missingProperty?: unknown }).missingProperty;\n if (typeof missing === 'string') {\n pointer = `${err.instancePath}/${escapePointerSegment(missing)}`;\n }\n } else if (err.keyword === 'additionalProperties') {\n const extra = (err.params as { additionalProperty?: unknown }).additionalProperty;\n if (typeof extra === 'string') {\n pointer = `${err.instancePath}/${escapePointerSegment(extra)}`;\n }\n }\n\n return {\n pointer,\n message: err.message ?? 'Validation failed.',\n keyword: err.keyword,\n schemaPointer: err.schemaPath ? err.schemaPath : undefined,\n };\n}\n\n/** Escape a JSON Pointer segment per RFC 6901 (~ becomes ~0, / becomes ~1). */\nfunction escapePointerSegment(segment: string): string {\n return segment.replace(/~/g, '~0').replace(/\\//g, '~1');\n}\n","/**\n * Canonicalize a {@link Takuhon} document into the form downstream consumers\n * (`@takuhon/api`, `@takuhon/ui`, `@takuhon/jsonld`) can rely on without\n * re-checking shape invariants.\n *\n * Two transformations only:\n * - **Empty-entry cleanup** on every localized field (`LocalizedTitle` /\n * `LocalizedBody`): entries whose string value is empty or whitespace-only\n * are removed so that locale fallback works field-by-field. When the\n * cleanup leaves an optional localized map empty, the map itself is\n * removed (the schema requires `minProperties: 1`).\n * - **Stable sort by `order`** on every list field (`links`, `careers`,\n * `projects`, `skills`). Items without an `order` move to the end while\n * preserving their original relative position (ES2019 stable sort).\n *\n * Design notes:\n * - The input is deep-cloned via `structuredClone`; the original is never\n * mutated. Callers may safely keep a reference to the value they passed in.\n * - `normalize` does *not* canonicalize BCP-47 tag casing nor trim string\n * content. The first is covered by the schema's `propertyNames` pattern and\n * `resolveLocale`'s case-insensitive lookup; the second would silently rewrite\n * author input and is out of scope for Phase 1.\n * - `normalize(normalize(x))` deep-equals `normalize(x)` (idempotent), and the\n * output re-validates against `takuhon.schema.json`. Both invariants are\n * enforced by the unit tests.\n */\n\nimport type {\n LocalizedBody,\n LocalizedTitle,\n Takuhon,\n NormalizedTakuhon,\n Profile,\n} from './types.js';\n\n/**\n * Return a normalized copy of `data`.\n *\n * @param data A takuhon document that has already passed {@link validate}.\n * @returns A new {@link NormalizedTakuhon} with localized empties dropped and\n * list fields sorted by `order`.\n */\nexport function normalize(data: Takuhon): NormalizedTakuhon {\n // A takuhon document is structurally pure JSON (string/number/boolean/null +\n // plain objects / arrays — no Date, Map, Set, BigInt, or functions), so a\n // round-trip through JSON gives an equivalent deep clone without depending\n // on `structuredClone`'s global type declaration (which moves between TS\n // `lib.es2022.d.ts` and `lib.dom.d.ts` across TypeScript major releases).\n const out = JSON.parse(JSON.stringify(data)) as Takuhon;\n\n // Defensive: the schema marks several top-level arrays as optional for\n // back-compat (the nine added in 0.2.0, `testScores` in 0.3.0, and\n // `recommendations` in 0.4.0), so a stored older profile read from KV after\n // an upgrade may arrive here without them. The TypeScript `Takuhon` shape\n // requires them; coerce missing values to `[]` so downstream iteration\n // never trips on `undefined`. Idempotent: arrays already present are left\n // untouched.\n const bag = out as unknown as Record<string, unknown>;\n for (const key of NORMALIZED_ARRAYS) {\n if (!Array.isArray(bag[key])) {\n bag[key] = [];\n }\n }\n\n normalizeProfile(out.profile);\n\n for (const link of out.links) {\n cleanOptionalLocalized(link, 'label');\n }\n out.links = stableSortByOrder(out.links);\n\n for (const career of out.careers) {\n cleanRequiredLocalized(career.organization);\n cleanRequiredLocalized(career.role);\n cleanOptionalLocalized(career, 'description');\n }\n out.careers = stableSortByOrder(out.careers);\n\n for (const project of out.projects) {\n cleanRequiredLocalized(project.title);\n cleanOptionalLocalized(project, 'description');\n }\n out.projects = stableSortByOrder(out.projects);\n\n out.skills = stableSortByOrder(out.skills);\n\n for (const cert of out.certifications) {\n cleanRequiredLocalized(cert.title);\n cleanRequiredLocalized(cert.issuingOrganization);\n }\n out.certifications = stableSortByOrder(out.certifications);\n\n for (const m of out.memberships) {\n cleanRequiredLocalized(m.organization);\n cleanOptionalLocalized(m, 'role');\n cleanOptionalLocalized(m, 'description');\n }\n out.memberships = stableSortByOrder(out.memberships);\n\n for (const v of out.volunteering) {\n cleanRequiredLocalized(v.organization);\n cleanRequiredLocalized(v.role);\n cleanOptionalLocalized(v, 'cause');\n cleanOptionalLocalized(v, 'description');\n }\n out.volunteering = stableSortByOrder(out.volunteering);\n\n for (const h of out.honors) {\n cleanRequiredLocalized(h.title);\n cleanRequiredLocalized(h.issuer);\n cleanOptionalLocalized(h, 'description');\n }\n out.honors = stableSortByOrder(out.honors);\n\n for (const e of out.education) {\n cleanRequiredLocalized(e.institution);\n cleanOptionalLocalized(e, 'degree');\n cleanOptionalLocalized(e, 'fieldOfStudy');\n cleanOptionalLocalized(e, 'description');\n }\n out.education = stableSortByOrder(out.education);\n\n for (const p of out.publications) {\n cleanRequiredLocalized(p.title);\n cleanOptionalLocalized(p, 'publisher');\n cleanOptionalLocalized(p, 'description');\n }\n out.publications = stableSortByOrder(out.publications);\n\n for (const l of out.languages) {\n cleanOptionalLocalized(l, 'displayName');\n }\n out.languages = stableSortByOrder(out.languages);\n\n for (const c of out.courses) {\n cleanRequiredLocalized(c.title);\n cleanOptionalLocalized(c, 'provider');\n cleanOptionalLocalized(c, 'description');\n }\n out.courses = stableSortByOrder(out.courses);\n\n for (const p of out.patents) {\n cleanRequiredLocalized(p.title);\n cleanOptionalLocalized(p, 'description');\n }\n out.patents = stableSortByOrder(out.patents);\n\n for (const t of out.testScores) {\n cleanRequiredLocalized(t.title);\n cleanOptionalLocalized(t, 'description');\n }\n out.testScores = stableSortByOrder(out.testScores);\n\n for (const r of out.recommendations) {\n cleanRequiredLocalized(r.body);\n cleanOptionalLocalized(r, 'relationship');\n cleanOptionalLocalized(r.author, 'headline');\n }\n out.recommendations = stableSortByOrder(out.recommendations);\n\n return out;\n}\n\nfunction normalizeProfile(profile: Profile): void {\n cleanRequiredLocalized(profile.displayName);\n cleanOptionalLocalized(profile, 'tagline');\n cleanOptionalLocalized(profile, 'bio');\n if (profile.avatar) {\n cleanOptionalLocalized(profile.avatar, 'alt');\n }\n if (profile.location) {\n cleanOptionalLocalized(profile.location, 'locality');\n cleanOptionalLocalized(profile.location, 'display');\n }\n}\n\n/** Remove empty / whitespace-only entries from a required localized map in place. */\nfunction cleanRequiredLocalized(map: LocalizedTitle | LocalizedBody): void {\n for (const key of Object.keys(map)) {\n const value = map[key];\n if (value === undefined || value.trim() === '') {\n delete map[key];\n }\n }\n}\n\n/**\n * Remove empty / whitespace-only entries from an optional localized map. When\n * the resulting map is empty, the property is removed from its parent so the\n * document remains schema-valid (`LocalizedTitle` / `LocalizedBody` require\n * `minProperties: 1`).\n */\nfunction cleanOptionalLocalized<\n K extends string,\n T extends Partial<Record<K, LocalizedTitle | LocalizedBody>>,\n>(parent: T, key: K): void {\n const map = parent[key];\n if (!map) return;\n for (const k of Object.keys(map)) {\n const value = map[k];\n if (value === undefined || value.trim() === '') {\n delete map[k];\n }\n }\n if (Object.keys(map).length === 0) {\n delete parent[key];\n }\n}\n\n/** Stable sort items by ascending `order`; entries without `order` go last. */\nfunction stableSortByOrder<T extends { order?: number }>(items: T[]): T[] {\n return items.slice().sort((a, b) => {\n const ao = a.order ?? Number.POSITIVE_INFINITY;\n const bo = b.order ?? Number.POSITIVE_INFINITY;\n return ao - bo;\n });\n}\n\nconst NORMALIZED_ARRAYS = [\n 'certifications',\n 'memberships',\n 'volunteering',\n 'honors',\n 'education',\n 'publications',\n 'languages',\n 'courses',\n 'patents',\n 'testScores',\n 'recommendations',\n] as const;\n","/**\n * BCP-47 locale-tag helpers shared by `normalize()` and `resolveLocale()`.\n *\n * These functions intentionally do not depend on `Intl.Locale`: the schema's\n * `propertyNames` pattern already guarantees structural validity for tags that\n * have passed validation, so this module only needs string-level operations\n * (case-insensitive lookup, primary-subtag fallback, simple regex shape check).\n * Keeping the implementation dependency-free also avoids platform differences\n * between Node, Workers, and modern browsers.\n */\n\n/** Same shape as `takuhon.schema.json`'s `propertyNames` for localized maps. */\nconst BCP47_PATTERN = /^[a-zA-Z]{2,3}(-[a-zA-Z0-9]+)*$/;\n\n/**\n * Return whether a string has the structural shape of a BCP-47 tag accepted\n * by `takuhon.schema.json`. This is a syntactic check only — `'zz'` passes\n * because it matches the regex even though it is not a registered subtag.\n * Semantic validity (registered language / region) is intentionally out of\n * scope; consumers that want it should compose `Intl.Locale` on top.\n */\nexport function isValidBcp47(tag: string): boolean {\n return BCP47_PATTERN.test(tag);\n}\n\n/**\n * Expand a tag into a list of progressively shorter candidates by dropping\n * trailing subtags, e.g. `'zh-Hant-TW' → ['zh-Hant-TW', 'zh-Hant', 'zh']`.\n * Returns the input unchanged for single-subtag inputs (`'en' → ['en']`),\n * and returns `[]` for tags that do not match the BCP-47 shape.\n */\nexport function expandRegional(tag: string): string[] {\n if (!isValidBcp47(tag)) return [];\n const parts = tag.split('-');\n const out: string[] = [];\n for (let i = parts.length; i >= 1; i--) {\n out.push(parts.slice(0, i).join('-'));\n }\n return out;\n}\n\n/** Compare two locale tags ignoring ASCII case (`'EN-us'` matches `'en-US'`). */\nexport function localeMatches(a: string, b: string): boolean {\n return a.toLowerCase() === b.toLowerCase();\n}\n\n/**\n * Look up a value from a locale-keyed map ignoring ASCII case.\n *\n * BCP-47 tags use canonical casing (`zh-Hant`, `pt-BR`) but the spec asks for\n * case-insensitive comparison so consumers can query with `EN-us` or `EN-US`\n * regardless of how the document was authored.\n */\nexport function lookupCaseInsensitive<T>(\n map: Record<string, T> | undefined,\n key: string,\n): T | undefined {\n if (!map) return undefined;\n const direct = map[key];\n if (direct !== undefined) return direct;\n const lower = key.toLowerCase();\n for (const k of Object.keys(map)) {\n if (k.toLowerCase() === lower) return map[k];\n }\n return undefined;\n}\n","/**\n * Reduce a multi-locale {@link Takuhon} document to a single requested locale.\n *\n * Builds a flat candidate chain from the function arguments and `data.settings`,\n * expanding each entry's regional subtag (e.g. `'en-US' → ['en-US', 'en']`),\n * deduplicating case-insensitively, then walks the chain **per field**. The\n * first candidate whose value is non-blank wins for that field; an empty entry\n * (`\"\"` / whitespace-only) falls through to the next candidate just like a\n * missing entry. This matches the spec semantics in [api.md §3.4] where empty\n * values are equivalent to absence.\n *\n * Design notes:\n * - Function arguments (`locale`, `fallbackLocale`) take precedence over\n * `settings.*`, in line with the spec's 7-tier list: HTTP-derived locales\n * (#1-#4) are resolved upstream by `@takuhon/api` and arrive here as\n * `locale` / `fallbackLocale`; `settings.defaultLocale` (#5),\n * `settings.fallbackLocale` (#6), and `settings.availableLocales[0]` (#7)\n * fill the tail.\n * - Invalid tags (`'zz_invalid'`, `'_'`, etc.) are silently dropped rather\n * than throwing. Resolution is best-effort: throwing on a malformed\n * `?lang=` query would push error handling responsibilities back into the\n * API layer for a recoverable case.\n * - A final rescue step appends every `availableLocales` entry so a request\n * with no matching candidate still produces a populated document. If even\n * that fails (only possible for hand-crafted inputs that bypassed\n * `validate`), required strings fall back to `''` and the caller's tests\n * catch the document-level regression.\n * - `resolvedLocale` records the tag that produced `profile.displayName`,\n * which is the field most consumers expose as the canonical locale of the\n * response (e.g. `meta.locale` in API responses, `<html lang>` in UI).\n */\n\nimport { expandRegional, isValidBcp47, lookupCaseInsensitive } from './locale-tag.js';\nimport type {\n Address,\n Avatar,\n Career,\n Certification,\n Course,\n Education,\n Honor,\n Language,\n Link,\n LocaleTag,\n LocalizedAddress,\n LocalizedAvatar,\n LocalizedBody,\n LocalizedCareer,\n LocalizedCertification,\n LocalizedCourse,\n LocalizedEducation,\n LocalizedHonor,\n LocalizedLanguage,\n LocalizedLink,\n LocalizedMembership,\n LocalizedPatent,\n LocalizedProfile,\n LocalizedProject,\n LocalizedPublication,\n LocalizedRecommendation,\n LocalizedRecommendationAuthor,\n LocalizedTakuhon,\n LocalizedTestScore,\n LocalizedTitle,\n LocalizedVolunteering,\n Membership,\n Patent,\n Profile,\n Project,\n Publication,\n Recommendation,\n RecommendationAuthor,\n Takuhon,\n TestScore,\n Volunteering,\n} from './types.js';\n\n/**\n * Resolve a takuhon document to a single locale.\n *\n * @param data A takuhon document (validated; ideally normalized first).\n * @param locale Caller-resolved request locale (e.g. from `?lang=` or\n * `Accept-Language`). Invalid tags are ignored.\n * @param fallbackLocale Caller-supplied secondary candidate when `locale`\n * misses. Invalid tags are ignored.\n */\nexport function resolveLocale(\n data: Takuhon,\n locale?: string,\n fallbackLocale?: string,\n): LocalizedTakuhon {\n const candidates = buildCandidates(data, locale, fallbackLocale);\n const displayPick = pickLocalizedWithTag(data.profile.displayName, candidates);\n\n return {\n schemaVersion: data.schemaVersion,\n profile: resolveProfile(data.profile, candidates, displayPick?.value ?? ''),\n links: data.links.map((l) => resolveLink(l, candidates)),\n careers: data.careers.map((c) => resolveCareer(c, candidates)),\n projects: data.projects.map((p) => resolveProject(p, candidates)),\n skills: data.skills,\n certifications: data.certifications.map((c) => resolveCertification(c, candidates)),\n memberships: data.memberships.map((m) => resolveMembership(m, candidates)),\n volunteering: data.volunteering.map((v) => resolveVolunteering(v, candidates)),\n honors: data.honors.map((h) => resolveHonor(h, candidates)),\n education: data.education.map((e) => resolveEducation(e, candidates)),\n publications: data.publications.map((p) => resolvePublication(p, candidates)),\n languages: data.languages.map((l) => resolveLanguage(l, candidates)),\n courses: data.courses.map((c) => resolveCourse(c, candidates)),\n patents: data.patents.map((p) => resolvePatent(p, candidates)),\n testScores: data.testScores.map((t) => resolveTestScore(t, candidates)),\n recommendations: data.recommendations.map((r) => resolveRecommendation(r, candidates)),\n contact: data.contact,\n settings: data.settings,\n meta: data.meta,\n resolvedLocale: displayPick?.tag ?? candidates[0] ?? '',\n };\n}\n\nfunction buildCandidates(\n data: Takuhon,\n locale: string | undefined,\n fallbackLocale: string | undefined,\n): LocaleTag[] {\n const raw: string[] = [];\n if (locale !== undefined) raw.push(...expandRegional(locale));\n if (fallbackLocale !== undefined) raw.push(...expandRegional(fallbackLocale));\n raw.push(...expandRegional(data.settings.defaultLocale));\n if (data.settings.fallbackLocale !== undefined) {\n raw.push(...expandRegional(data.settings.fallbackLocale));\n }\n for (const tag of data.settings.availableLocales) {\n raw.push(...expandRegional(tag));\n }\n return dedupCaseInsensitive(raw);\n}\n\nfunction dedupCaseInsensitive(tags: string[]): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const tag of tags) {\n if (!isValidBcp47(tag)) continue;\n const lower = tag.toLowerCase();\n if (seen.has(lower)) continue;\n seen.add(lower);\n out.push(tag);\n }\n return out;\n}\n\nfunction pickLocalizedWithTag(\n field: LocalizedTitle | LocalizedBody | undefined,\n candidates: LocaleTag[],\n): { value: string; tag: LocaleTag } | undefined {\n if (!field) return undefined;\n for (const tag of candidates) {\n const hit = lookupCaseInsensitive(field, tag);\n if (hit !== undefined && hit.trim() !== '') {\n return { value: hit, tag };\n }\n }\n return undefined;\n}\n\nfunction pickLocalized(\n field: LocalizedTitle | LocalizedBody | undefined,\n candidates: LocaleTag[],\n): string | undefined {\n return pickLocalizedWithTag(field, candidates)?.value;\n}\n\nfunction resolveProfile(\n profile: Profile,\n candidates: LocaleTag[],\n displayName: string,\n): LocalizedProfile {\n const out: LocalizedProfile = { displayName };\n\n const tagline = pickLocalized(profile.tagline, candidates);\n if (tagline !== undefined) out.tagline = tagline;\n\n const bio = pickLocalized(profile.bio, candidates);\n if (bio !== undefined) out.bio = bio;\n\n if (profile.avatar) out.avatar = resolveAvatar(profile.avatar, candidates);\n if (profile.location) out.location = resolveAddress(profile.location, candidates);\n\n return out;\n}\n\nfunction resolveAvatar(avatar: Avatar, candidates: LocaleTag[]): LocalizedAvatar {\n const out: LocalizedAvatar = { url: avatar.url };\n const alt = pickLocalized(avatar.alt, candidates);\n if (alt !== undefined) out.alt = alt;\n return out;\n}\n\nfunction resolveAddress(address: Address, candidates: LocaleTag[]): LocalizedAddress {\n const out: LocalizedAddress = {};\n if (address.country !== undefined) out.country = address.country;\n if (address.region !== undefined) out.region = address.region;\n const locality = pickLocalized(address.locality, candidates);\n if (locality !== undefined) out.locality = locality;\n const display = pickLocalized(address.display, candidates);\n if (display !== undefined) out.display = display;\n return out;\n}\n\nfunction resolveLink(link: Link, candidates: LocaleTag[]): LocalizedLink {\n const label = pickLocalized(link.label, candidates);\n if (link.type === 'custom') {\n const out: LocalizedLink = {\n id: link.id,\n type: 'custom',\n url: link.url,\n iconUrl: link.iconUrl,\n };\n if (label !== undefined) out.label = label;\n if (link.featured !== undefined) out.featured = link.featured;\n if (link.order !== undefined) out.order = link.order;\n return out;\n }\n const out: LocalizedLink = {\n id: link.id,\n type: link.type,\n url: link.url,\n };\n if (label !== undefined) out.label = label;\n if (link.featured !== undefined) out.featured = link.featured;\n if (link.order !== undefined) out.order = link.order;\n if (link.iconUrl !== undefined) out.iconUrl = link.iconUrl;\n return out;\n}\n\nfunction resolveCareer(career: Career, candidates: LocaleTag[]): LocalizedCareer {\n const out: LocalizedCareer = {\n id: career.id,\n organization: pickLocalized(career.organization, candidates) ?? '',\n role: pickLocalized(career.role, candidates) ?? '',\n startDate: career.startDate,\n };\n const description = pickLocalized(career.description, candidates);\n if (description !== undefined) out.description = description;\n if (career.endDate !== undefined) out.endDate = career.endDate;\n if (career.isCurrent !== undefined) out.isCurrent = career.isCurrent;\n if (career.url !== undefined) out.url = career.url;\n if (career.order !== undefined) out.order = career.order;\n if (career.location) out.location = resolveAddress(career.location, candidates);\n return out;\n}\n\nfunction resolveProject(project: Project, candidates: LocaleTag[]): LocalizedProject {\n const out: LocalizedProject = {\n id: project.id,\n title: pickLocalized(project.title, candidates) ?? '',\n };\n const description = pickLocalized(project.description, candidates);\n if (description !== undefined) out.description = description;\n if (project.url !== undefined) out.url = project.url;\n if (project.tags !== undefined) out.tags = project.tags;\n if (project.relatedCareerId !== undefined) out.relatedCareerId = project.relatedCareerId;\n if (project.startDate !== undefined) out.startDate = project.startDate;\n if (project.endDate !== undefined) out.endDate = project.endDate;\n if (project.highlighted !== undefined) out.highlighted = project.highlighted;\n if (project.order !== undefined) out.order = project.order;\n return out;\n}\n\nfunction resolveCertification(\n cert: Certification,\n candidates: LocaleTag[],\n): LocalizedCertification {\n const out: LocalizedCertification = {\n id: cert.id,\n title: pickLocalized(cert.title, candidates) ?? '',\n issuingOrganization: pickLocalized(cert.issuingOrganization, candidates) ?? '',\n issueDate: cert.issueDate,\n };\n if (cert.expirationDate !== undefined) out.expirationDate = cert.expirationDate;\n if (cert.credentialId !== undefined) out.credentialId = cert.credentialId;\n if (cert.url !== undefined) out.url = cert.url;\n if (cert.order !== undefined) out.order = cert.order;\n return out;\n}\n\nfunction resolveMembership(membership: Membership, candidates: LocaleTag[]): LocalizedMembership {\n const out: LocalizedMembership = {\n id: membership.id,\n organization: pickLocalized(membership.organization, candidates) ?? '',\n startDate: membership.startDate,\n };\n const role = pickLocalized(membership.role, candidates);\n if (role !== undefined) out.role = role;\n const description = pickLocalized(membership.description, candidates);\n if (description !== undefined) out.description = description;\n if (membership.endDate !== undefined) out.endDate = membership.endDate;\n if (membership.isCurrent !== undefined) out.isCurrent = membership.isCurrent;\n if (membership.url !== undefined) out.url = membership.url;\n if (membership.order !== undefined) out.order = membership.order;\n return out;\n}\n\nfunction resolveVolunteering(v: Volunteering, candidates: LocaleTag[]): LocalizedVolunteering {\n const out: LocalizedVolunteering = {\n id: v.id,\n organization: pickLocalized(v.organization, candidates) ?? '',\n role: pickLocalized(v.role, candidates) ?? '',\n startDate: v.startDate,\n };\n const cause = pickLocalized(v.cause, candidates);\n if (cause !== undefined) out.cause = cause;\n const description = pickLocalized(v.description, candidates);\n if (description !== undefined) out.description = description;\n if (v.endDate !== undefined) out.endDate = v.endDate;\n if (v.isCurrent !== undefined) out.isCurrent = v.isCurrent;\n if (v.url !== undefined) out.url = v.url;\n if (v.order !== undefined) out.order = v.order;\n return out;\n}\n\nfunction resolveHonor(honor: Honor, candidates: LocaleTag[]): LocalizedHonor {\n const out: LocalizedHonor = {\n id: honor.id,\n title: pickLocalized(honor.title, candidates) ?? '',\n issuer: pickLocalized(honor.issuer, candidates) ?? '',\n date: honor.date,\n };\n const description = pickLocalized(honor.description, candidates);\n if (description !== undefined) out.description = description;\n if (honor.url !== undefined) out.url = honor.url;\n if (honor.order !== undefined) out.order = honor.order;\n return out;\n}\n\nfunction resolveEducation(edu: Education, candidates: LocaleTag[]): LocalizedEducation {\n const out: LocalizedEducation = {\n id: edu.id,\n institution: pickLocalized(edu.institution, candidates) ?? '',\n startDate: edu.startDate,\n };\n const degree = pickLocalized(edu.degree, candidates);\n if (degree !== undefined) out.degree = degree;\n const fieldOfStudy = pickLocalized(edu.fieldOfStudy, candidates);\n if (fieldOfStudy !== undefined) out.fieldOfStudy = fieldOfStudy;\n const description = pickLocalized(edu.description, candidates);\n if (description !== undefined) out.description = description;\n if (edu.grade !== undefined) out.grade = edu.grade;\n if (edu.endDate !== undefined) out.endDate = edu.endDate;\n if (edu.isCurrent !== undefined) out.isCurrent = edu.isCurrent;\n if (edu.url !== undefined) out.url = edu.url;\n if (edu.order !== undefined) out.order = edu.order;\n return out;\n}\n\nfunction resolvePublication(pub: Publication, candidates: LocaleTag[]): LocalizedPublication {\n const out: LocalizedPublication = {\n id: pub.id,\n title: pickLocalized(pub.title, candidates) ?? '',\n date: pub.date,\n };\n const publisher = pickLocalized(pub.publisher, candidates);\n if (publisher !== undefined) out.publisher = publisher;\n const description = pickLocalized(pub.description, candidates);\n if (description !== undefined) out.description = description;\n if (pub.url !== undefined) out.url = pub.url;\n if (pub.doi !== undefined) out.doi = pub.doi;\n if (pub.coAuthors !== undefined) out.coAuthors = pub.coAuthors;\n if (pub.order !== undefined) out.order = pub.order;\n return out;\n}\n\nfunction resolveLanguage(lang: Language, candidates: LocaleTag[]): LocalizedLanguage {\n const out: LocalizedLanguage = {\n id: lang.id,\n language: lang.language,\n proficiency: lang.proficiency,\n };\n const displayName = pickLocalized(lang.displayName, candidates);\n if (displayName !== undefined) out.displayName = displayName;\n if (lang.order !== undefined) out.order = lang.order;\n return out;\n}\n\nfunction resolveCourse(course: Course, candidates: LocaleTag[]): LocalizedCourse {\n const out: LocalizedCourse = {\n id: course.id,\n title: pickLocalized(course.title, candidates) ?? '',\n };\n const provider = pickLocalized(course.provider, candidates);\n if (provider !== undefined) out.provider = provider;\n if (course.courseNumber !== undefined) out.courseNumber = course.courseNumber;\n const description = pickLocalized(course.description, candidates);\n if (description !== undefined) out.description = description;\n if (course.completionDate !== undefined) out.completionDate = course.completionDate;\n if (course.certificateUrl !== undefined) out.certificateUrl = course.certificateUrl;\n if (course.relatedEducationId !== undefined) out.relatedEducationId = course.relatedEducationId;\n if (course.order !== undefined) out.order = course.order;\n return out;\n}\n\nfunction resolvePatent(patent: Patent, candidates: LocaleTag[]): LocalizedPatent {\n const out: LocalizedPatent = {\n id: patent.id,\n title: pickLocalized(patent.title, candidates) ?? '',\n patentNumber: patent.patentNumber,\n status: patent.status,\n };\n if (patent.office !== undefined) out.office = patent.office;\n const description = pickLocalized(patent.description, candidates);\n if (description !== undefined) out.description = description;\n if (patent.filingDate !== undefined) out.filingDate = patent.filingDate;\n if (patent.grantDate !== undefined) out.grantDate = patent.grantDate;\n if (patent.url !== undefined) out.url = patent.url;\n if (patent.coInventors !== undefined) out.coInventors = patent.coInventors;\n if (patent.order !== undefined) out.order = patent.order;\n return out;\n}\n\nfunction resolveTestScore(testScore: TestScore, candidates: LocaleTag[]): LocalizedTestScore {\n const out: LocalizedTestScore = {\n id: testScore.id,\n title: pickLocalized(testScore.title, candidates) ?? '',\n score: testScore.score,\n date: testScore.date,\n };\n const description = pickLocalized(testScore.description, candidates);\n if (description !== undefined) out.description = description;\n if (testScore.relatedEducationId !== undefined) {\n out.relatedEducationId = testScore.relatedEducationId;\n }\n if (testScore.url !== undefined) out.url = testScore.url;\n if (testScore.order !== undefined) out.order = testScore.order;\n return out;\n}\n\nfunction resolveRecommendation(\n recommendation: Recommendation,\n candidates: LocaleTag[],\n): LocalizedRecommendation {\n const out: LocalizedRecommendation = {\n id: recommendation.id,\n body: pickLocalized(recommendation.body, candidates) ?? '',\n author: resolveRecommendationAuthor(recommendation.author, candidates),\n };\n const relationship = pickLocalized(recommendation.relationship, candidates);\n if (relationship !== undefined) out.relationship = relationship;\n if (recommendation.date !== undefined) out.date = recommendation.date;\n if (recommendation.relatedCareerId !== undefined) {\n out.relatedCareerId = recommendation.relatedCareerId;\n }\n if (recommendation.relatedEducationId !== undefined) {\n out.relatedEducationId = recommendation.relatedEducationId;\n }\n if (recommendation.order !== undefined) out.order = recommendation.order;\n return out;\n}\n\nfunction resolveRecommendationAuthor(\n author: RecommendationAuthor,\n candidates: LocaleTag[],\n): LocalizedRecommendationAuthor {\n const out: LocalizedRecommendationAuthor = { name: author.name };\n const headline = pickLocalized(author.headline, candidates);\n if (headline !== undefined) out.headline = headline;\n if (author.url !== undefined) out.url = author.url;\n return out;\n}\n","/**\n * Generate Schema.org JSON-LD from a {@link LocalizedTakuhon} document.\n *\n * Emits a `ProfilePage` whose `mainEntity` is the `Person` described by the\n * input. Mapping rules follow the published schema.org mapping spec; the\n * relevant invariants are exercised by the unit tests.\n *\n * Design notes:\n * - Input is the output of `resolveLocale()`, so every localized field is\n * already a single string. No locale fallback happens here.\n * - All optional keys are omitted (not set to `null` / `undefined`) when their\n * source value is absent or empty, so consumers can shallow-merge or\n * `JSON.stringify` the result without post-processing.\n * - The canonical URL surfaced as `ProfilePage.url`, `Person.@id`, and\n * `Person.url` is derived from a single `links[]` entry: `type: 'website'`\n * with `featured: true`. The first match wins (stable after `normalize()`).\n * When no such link exists the three URL-bearing keys are omitted entirely;\n * no placeholder is fabricated.\n * - `profile.tagline` is intentionally not surfaced. `description` carries\n * `profile.bio` only, matching the spec exemplar. Phase 2 may revisit.\n * - `contact.email` is surfaced only when `contact.showEmail === true`\n * (privacy by default).\n * - URLs pass through verbatim. Relative paths in the input remain relative\n * in the output; absolutization is the API/UI layer's responsibility.\n * - Field insertion order on each emitted object is fixed so\n * `JSON.stringify(result)` is deterministic for a given input.\n */\n\nimport type {\n Contact,\n LinkType,\n LocalizedAddress,\n LocalizedAvatar,\n LocalizedCareer,\n LocalizedCertification,\n LocalizedCourse,\n LocalizedEducation,\n LocalizedHonor,\n LocalizedLanguage,\n LocalizedLink,\n LocalizedMembership,\n LocalizedPatent,\n LocalizedProject,\n LocalizedPublication,\n LocalizedTakuhon,\n LocalizedVolunteering,\n Skill,\n} from './types.js';\n\n/**\n * `links[].type` values that count as identity-bearing for the purpose of\n * `Person.sameAs`. `email`, `rss`, and `custom` are excluded: they either\n * carry no identity assertion (`custom`) or are not a profile URL on a\n * third-party platform (`email`, `rss`).\n */\nconst SAMEAS_IDENTITY_TYPES: ReadonlySet<LinkType> = new Set<LinkType>([\n 'github',\n 'gitlab',\n 'linkedin',\n 'x',\n 'mastodon',\n 'bluesky',\n 'instagram',\n 'youtube',\n 'threads',\n 'facebook',\n 'website',\n 'blog',\n]);\n\n/**\n * Build the `Person` JSON-LD object for `data`.\n *\n * @param data A locale-resolved takuhon document.\n * @returns A Schema.org `Person` object. `@context` is included so the\n * returned object is valid as a standalone JSON-LD document.\n */\nexport function generatePersonJsonLd(data: LocalizedTakuhon): object {\n const person = buildPerson(data, deriveCanonicalUrl(data));\n return { '@context': 'https://schema.org', ...person };\n}\n\n/**\n * Build the `ProfilePage` JSON-LD object for `data`, with `Person` inlined\n * as `mainEntity`.\n *\n * @param data A locale-resolved takuhon document.\n */\nexport function generateProfilePageJsonLd(data: LocalizedTakuhon): object {\n const canonicalUrl = deriveCanonicalUrl(data);\n const person = buildPerson(data, canonicalUrl);\n\n const out: Record<string, unknown> = {};\n out['@context'] = 'https://schema.org';\n out['@type'] = 'ProfilePage';\n if (canonicalUrl !== undefined) out.url = canonicalUrl;\n out.inLanguage = data.resolvedLocale;\n if (data.meta.createdAt !== undefined) out.dateCreated = data.meta.createdAt;\n if (data.meta.updatedAt !== undefined) out.dateModified = data.meta.updatedAt;\n if (data.profile.avatar !== undefined) out.primaryImageOfPage = data.profile.avatar.url;\n out.mainEntity = person;\n return out;\n}\n\n/**\n * Build the array of JSON-LD objects to embed in a single\n * `<script type=\"application/ld+json\">` tag.\n *\n * Phase 1 emits a single-element array containing the `ProfilePage`; the\n * `Person` is inlined there as `mainEntity`. The array shape leaves room\n * for later additions (e.g. `WebSite`) without changing the public surface.\n */\nexport function generateJsonLd(data: LocalizedTakuhon): object[] {\n return [generateProfilePageJsonLd(data)];\n}\n\nfunction deriveCanonicalUrl(data: LocalizedTakuhon): string | undefined {\n const featured = data.links.find((l) => l.type === 'website' && l.featured === true);\n return featured?.url;\n}\n\nfunction buildPerson(data: LocalizedTakuhon, canonicalUrl: string | undefined): object {\n const {\n profile,\n careers,\n projects,\n links,\n skills,\n contact,\n certifications,\n memberships,\n volunteering,\n honors,\n education,\n publications,\n languages,\n courses,\n patents,\n } = data;\n\n const out: Record<string, unknown> = {};\n out['@type'] = 'Person';\n if (canonicalUrl !== undefined) out['@id'] = `${canonicalUrl}#person`;\n out.name = profile.displayName;\n if (profile.bio !== undefined) out.description = profile.bio;\n\n const image = buildImage(profile.avatar);\n if (image !== undefined) out.image = image;\n\n if (canonicalUrl !== undefined) out.url = canonicalUrl;\n\n const { current, past } = partitionCareers(careers);\n const roleFields = buildCurrentRoleFields(current);\n if (roleFields.jobTitle !== undefined) out.jobTitle = roleFields.jobTitle;\n if (roleFields.worksFor !== undefined) out.worksFor = roleFields.worksFor;\n\n const address = buildAddress(profile.location);\n if (address !== undefined) out.address = address;\n\n const email = buildEmail(contact);\n if (email !== undefined) out.email = email;\n\n const knowsAbout = buildKnowsAbout(skills);\n if (knowsAbout !== undefined) out.knowsAbout = knowsAbout;\n\n const knowsLanguage = buildKnowsLanguage(languages);\n if (knowsLanguage !== undefined) out.knowsLanguage = knowsLanguage;\n\n const hasCredential = buildCredentials(certifications);\n if (hasCredential !== undefined) out.hasCredential = hasCredential;\n\n const memberOf = buildMemberOf(memberships);\n if (memberOf !== undefined) out.memberOf = memberOf;\n\n const alumniOf = buildAlumniOf(education);\n if (alumniOf !== undefined) out.alumniOf = alumniOf;\n\n const award = buildAwards(honors);\n if (award !== undefined) out.award = award;\n\n const sameAs = buildSameAs(links);\n if (sameAs !== undefined) out.sameAs = sameAs;\n\n const subjectOf = [\n ...buildPastRoles(past),\n ...buildProjects(projects),\n ...buildVolunteeringRoles(volunteering),\n ...buildPublications(publications),\n ...buildCourses(courses),\n ...buildPatentWorks(patents),\n ];\n if (subjectOf.length > 0) out.subjectOf = subjectOf;\n\n return out;\n}\n\nfunction buildImage(avatar: LocalizedAvatar | undefined): object | undefined {\n if (!avatar) return undefined;\n const out: Record<string, unknown> = {};\n out['@type'] = 'ImageObject';\n out.url = avatar.url;\n if (avatar.alt !== undefined) out.caption = avatar.alt;\n return out;\n}\n\nfunction buildAddress(location: LocalizedAddress | undefined): object | undefined {\n if (!location) return undefined;\n const hasAny =\n location.country !== undefined ||\n location.region !== undefined ||\n location.locality !== undefined;\n if (!hasAny) return undefined;\n // `location.display` is intentionally not surfaced: it is a UI-facing\n // pre-formatted string and would duplicate the structured fields here.\n const out: Record<string, unknown> = {};\n out['@type'] = 'PostalAddress';\n if (location.country !== undefined) out.addressCountry = location.country;\n if (location.region !== undefined) out.addressRegion = location.region;\n if (location.locality !== undefined) out.addressLocality = location.locality;\n return out;\n}\n\nfunction partitionCareers(careers: LocalizedCareer[]): {\n current: LocalizedCareer[];\n past: LocalizedCareer[];\n} {\n const current: LocalizedCareer[] = [];\n const past: LocalizedCareer[] = [];\n for (const c of careers) {\n if (c.isCurrent === true) current.push(c);\n else past.push(c);\n }\n return { current, past };\n}\n\nfunction buildCurrentRoleFields(current: LocalizedCareer[]): {\n jobTitle?: string;\n worksFor?: object;\n} {\n const head = current[0];\n if (head === undefined) return {};\n const out: { jobTitle?: string; worksFor?: object } = {};\n if (head.role !== '') out.jobTitle = head.role;\n out.worksFor = buildWorksFor(head);\n return out;\n}\n\nfunction buildWorksFor(career: LocalizedCareer): object {\n const out: Record<string, unknown> = {};\n out['@type'] = 'Organization';\n out.name = career.organization;\n if (career.url !== undefined) out.url = career.url;\n return out;\n}\n\nfunction buildPastRoles(past: LocalizedCareer[]): object[] {\n return past.map((c) => {\n const out: Record<string, unknown> = {};\n out['@type'] = 'WorkRole';\n out.name = c.role;\n out.memberOf = { '@type': 'Organization', name: c.organization };\n out.startDate = c.startDate;\n // `null` denotes an unbounded position; omit so the published JSON-LD\n // does not carry an explicit `null`.\n if (c.endDate !== undefined && c.endDate !== null) out.endDate = c.endDate;\n return out;\n });\n}\n\nfunction buildProjects(projects: LocalizedProject[]): object[] {\n return projects.map((p) => {\n const out: Record<string, unknown> = {};\n out['@type'] = 'CreativeWork';\n out.name = p.title;\n if (p.url !== undefined) out.url = p.url;\n if (p.startDate !== undefined) out.datePublished = p.startDate;\n if (p.tags !== undefined && p.tags.length > 0) out.about = p.tags;\n return out;\n });\n}\n\nfunction buildSameAs(links: LocalizedLink[]): string[] | undefined {\n const out = links.filter((l) => SAMEAS_IDENTITY_TYPES.has(l.type)).map((l) => l.url);\n return out.length === 0 ? undefined : out;\n}\n\nfunction buildKnowsAbout(skills: Skill[]): string[] | undefined {\n if (skills.length === 0) return undefined;\n return skills.map((s) => s.label);\n}\n\nfunction buildEmail(contact: Contact): string | undefined {\n if (contact.showEmail !== true) return undefined;\n if (typeof contact.email !== 'string' || contact.email.length === 0) return undefined;\n return contact.email;\n}\n\nfunction buildKnowsLanguage(languages: LocalizedLanguage[]): string[] | undefined {\n if (languages.length === 0) return undefined;\n return languages.map((l) => l.language);\n}\n\nfunction buildCredentials(certifications: LocalizedCertification[]): object[] | undefined {\n if (certifications.length === 0) return undefined;\n return certifications.map((c) => {\n const out: Record<string, unknown> = {};\n out['@type'] = 'EducationalOccupationalCredential';\n if (c.title !== '') out.name = c.title;\n out.credentialCategory = 'certification';\n if (c.issuingOrganization !== '') {\n out.recognizedBy = {\n '@type': 'Organization',\n name: c.issuingOrganization,\n };\n }\n out.dateCreated = c.issueDate;\n if (c.expirationDate !== undefined && c.expirationDate !== null) {\n out.expires = c.expirationDate;\n }\n if (c.credentialId !== undefined) out.identifier = c.credentialId;\n if (c.url !== undefined) out.url = c.url;\n return out;\n });\n}\n\nfunction buildMemberOf(memberships: LocalizedMembership[]): object[] | undefined {\n if (memberships.length === 0) return undefined;\n // Schema.org Role wrapper pattern: the outer OrganizationRole\n // carries the role/date metadata; the inner `memberOf` Organization names the\n // body itself.\n return memberships.map((m) => {\n const out: Record<string, unknown> = {};\n out['@type'] = 'OrganizationRole';\n if (m.role !== undefined) out.roleName = m.role;\n out.startDate = m.startDate;\n if (m.endDate !== undefined && m.endDate !== null) out.endDate = m.endDate;\n if (m.description !== undefined) out.description = m.description;\n const org: Record<string, unknown> = { '@type': 'Organization', name: m.organization };\n if (m.url !== undefined) org.url = m.url;\n out.memberOf = org;\n return out;\n });\n}\n\nfunction buildAlumniOf(education: LocalizedEducation[]): object[] | undefined {\n if (education.length === 0) return undefined;\n // Schema.org Role wrapper pattern: outer OrganizationRole carries date +\n // concatenated degree/fieldOfStudy as roleName; inner `alumniOf` names\n // the EducationalOrganization.\n return education.map((e) => {\n const out: Record<string, unknown> = {};\n out['@type'] = 'OrganizationRole';\n const roleName = composeRoleName(e.degree, e.fieldOfStudy);\n if (roleName !== undefined) out.roleName = roleName;\n out.startDate = e.startDate;\n if (e.endDate !== undefined && e.endDate !== null) out.endDate = e.endDate;\n const description = composeEducationDescription(e.description, e.grade);\n if (description !== undefined) out.description = description;\n const org: Record<string, unknown> = {\n '@type': 'EducationalOrganization',\n name: e.institution,\n };\n if (e.url !== undefined) org.url = e.url;\n out.alumniOf = org;\n return out;\n });\n}\n\nfunction composeRoleName(\n degree: string | undefined,\n fieldOfStudy: string | undefined,\n): string | undefined {\n if (degree === undefined && fieldOfStudy === undefined) return undefined;\n if (degree !== undefined && fieldOfStudy !== undefined) return `${degree} (${fieldOfStudy})`;\n return degree ?? fieldOfStudy;\n}\n\nfunction composeEducationDescription(\n description: string | undefined,\n grade: string | undefined,\n): string | undefined {\n // `grade` may have already been stripped by the API privacy filter; if it\n // reaches us, prepend a labelled line to the description.\n if (grade !== undefined && description !== undefined) return `Grade: ${grade}. ${description}`;\n if (grade !== undefined) return `Grade: ${grade}`;\n return description;\n}\n\nfunction buildAwards(honors: LocalizedHonor[]): string[] | undefined {\n if (honors.length === 0) return undefined;\n return honors.map((h) => `${h.title} (${h.issuer}, ${h.date})`);\n}\n\nfunction buildVolunteeringRoles(volunteering: LocalizedVolunteering[]): object[] {\n return volunteering.map((v) => {\n const out: Record<string, unknown> = {};\n // Schema.org `VolunteerRole` is a pending property; we use the stable\n // `Role` type with `roleName` so indexers without VolunteerRole support\n // still read meaningful data.\n out['@type'] = 'Role';\n out.roleName = v.role;\n out.startDate = v.startDate;\n if (v.endDate !== undefined && v.endDate !== null) out.endDate = v.endDate;\n const description = composeVolunteeringDescription(v.cause, v.description);\n if (description !== undefined) out.description = description;\n const org: Record<string, unknown> = { '@type': 'Organization', name: v.organization };\n if (v.url !== undefined) org.url = v.url;\n out.memberOf = org;\n return out;\n });\n}\n\nfunction composeVolunteeringDescription(\n cause: string | undefined,\n description: string | undefined,\n): string | undefined {\n if (cause !== undefined && description !== undefined) return `Cause: ${cause}. ${description}`;\n if (cause !== undefined) return `Cause: ${cause}`;\n return description;\n}\n\nfunction buildPublications(publications: LocalizedPublication[]): object[] {\n return publications.map((p) => {\n const out: Record<string, unknown> = {};\n out['@type'] = 'ScholarlyArticle';\n out.name = p.title;\n if (p.publisher !== undefined) {\n out.publisher = { '@type': 'Organization', name: p.publisher };\n }\n out.datePublished = p.date;\n if (p.url !== undefined) out.url = p.url;\n if (p.doi !== undefined) {\n out.identifier = { '@type': 'PropertyValue', propertyID: 'DOI', value: p.doi };\n }\n if (p.coAuthors !== undefined && p.coAuthors.length > 0) {\n out.author = p.coAuthors.map((name) => ({ '@type': 'Person', name }));\n }\n return out;\n });\n}\n\nfunction buildCourses(courses: LocalizedCourse[]): object[] {\n return courses.map((c) => {\n const out: Record<string, unknown> = {};\n out['@type'] = 'Course';\n out.name = c.title;\n if (c.provider !== undefined) {\n out.provider = { '@type': 'Organization', name: c.provider };\n }\n if (c.courseNumber !== undefined) out.courseCode = c.courseNumber;\n if (c.certificateUrl !== undefined) out.url = c.certificateUrl;\n if (c.completionDate !== undefined) {\n // Schema.org Course has no direct date property; dates live on\n // CourseInstance via hasCourseInstance.\n out.hasCourseInstance = {\n '@type': 'CourseInstance',\n endDate: c.completionDate,\n };\n }\n return out;\n });\n}\n\nfunction buildPatentWorks(patents: LocalizedPatent[]): object[] {\n return patents.map((p) => {\n const out: Record<string, unknown> = {};\n // Schema.org Patent is not in the released vocabulary; emit CreativeWork\n // with additionalType pointing at the pending Patent URL so consumers\n // that recognize it can specialize, while others fall back gracefully.\n out['@type'] = 'CreativeWork';\n out.additionalType = 'https://schema.org/Patent';\n out.name = p.title;\n out.identifier = p.patentNumber;\n if (p.office !== undefined) {\n out.publisher = { '@type': 'Organization', name: p.office };\n }\n out.creativeWorkStatus = p.status;\n if (p.grantDate !== undefined) {\n out.datePublished = p.grantDate;\n } else if (p.filingDate !== undefined) {\n out.dateCreated = p.filingDate;\n }\n if (p.url !== undefined) out.url = p.url;\n if (p.coInventors !== undefined && p.coInventors.length > 0) {\n out.author = p.coInventors.map((name) => ({ '@type': 'Person', name }));\n }\n return out;\n });\n}\n","/**\n * Export and import for takuhon profile documents.\n *\n * {@link exportTakuhon} serialises a {@link Takuhon} document into a transport\n * form ({@link ExportedTakuhon}) that can be persisted to a file, an API\n * response, or any other byte-oriented sink. {@link importTakuhon} is the\n * inverse: it validates the input and returns a {@link Takuhon}.\n *\n * Scope of these helpers (deliberately narrow):\n * - Pure, in-memory data transforms — no I/O, no storage adapter coupling.\n * - {@link importTakuhon} **does not** auto-migrate older `schemaVersion`\n * values. Cross-version handling belongs to the CLI / API layer, which\n * composes `importTakuhon` + {@link migrateTakuhon} + storage adapters as\n * spelled out in operational-lifecycle §5.3.\n * - Round-trip equivalence (operational-lifecycle §5.1) is preserved up to\n * the documented `meta.updatedAt` exception.\n *\n * Asset embedding (Base64) and backup creation are out of scope here; both\n * are the storage / API layer's responsibility.\n */\n\nimport type { Takuhon } from './types.js';\nimport { validate, type ValidationError } from './validate.js';\n\n/**\n * Structural alias of {@link Takuhon}: the transport form is the document\n * itself. A wrapping envelope (e.g. `{ format, version, data, hash }`) is\n * intentionally avoided in Phase 1 — adding one later would be a breaking\n * change to the `GET /api/admin/export` response shape and would require a major\n * version bump of `@takuhon/core`.\n */\nexport type ExportedTakuhon = Takuhon;\n\n/** Options for {@link exportTakuhon}. */\nexport interface ExportOptions {\n /**\n * When `true` (default), `meta.updatedAt` is overwritten with the current\n * ISO-8601 timestamp. Set to `false` for byte-for-byte reproducible\n * exports (e.g. roundtrip tests).\n *\n * Round-trip equivalence per operational-lifecycle §5.1 explicitly lists\n * `meta.updatedAt` as the allowed exception.\n */\n updateTimestamp?: boolean;\n}\n\n/**\n * Thrown by {@link importTakuhon} when the input fails schema validation\n * (including an unsupported `schemaVersion`). The `errors` field carries\n * the same {@link ValidationError} list that `validate()` would have\n * returned, so the API layer can map them onto RFC 7807.\n */\nexport class ImportError extends Error {\n readonly errors?: ValidationError[];\n\n constructor(message: string, options?: { cause?: unknown; errors?: ValidationError[] }) {\n super(message, { cause: options?.cause });\n this.name = 'ImportError';\n this.errors = options?.errors;\n }\n}\n\n/**\n * Serialise a {@link Takuhon} into its transport form. The input is\n * deep-cloned via `JSON.parse(JSON.stringify(...))`; the original is never\n * mutated.\n */\nexport function exportTakuhon(data: Takuhon, options: ExportOptions = {}): ExportedTakuhon {\n const out = JSON.parse(JSON.stringify(data)) as ExportedTakuhon;\n if (options.updateTimestamp !== false) {\n out.meta = { ...out.meta, updatedAt: new Date().toISOString() };\n }\n return out;\n}\n\n/**\n * Validate an {@link ExportedTakuhon} and return it as a {@link Takuhon}.\n *\n * On schema validation failure (including an unsupported `schemaVersion`)\n * throws an {@link ImportError} with the structured `errors` attached. The\n * input is not mutated. The return value is a deep clone, so subsequent\n * caller mutations cannot reach back into the supplied document.\n *\n * Cross-version inputs (older `schemaVersion`) are out of scope: callers\n * (CLI / API layer) should run {@link migrateTakuhon} before calling this.\n */\nexport function importTakuhon(data: ExportedTakuhon): Takuhon {\n const result = validate(data);\n if (!result.ok) {\n throw new ImportError('imported document failed schema validation', { errors: result.errors });\n }\n return JSON.parse(JSON.stringify(result.data)) as Takuhon;\n}\n","/**\n * Public-endpoint privacy filter for takuhon profile documents.\n *\n * Strips fields that the spec's privacy posture marks as opt-in for public\n * exposure, before the document reaches a public reader (a public API\n * response, a statically built page, …). The filter is deliberately\n * conservative: when `meta.privacy` is absent the most restrictive\n * interpretation applies (everything sensitive is hidden), and the operator\n * must explicitly opt into disclosure by setting the relevant flag to\n * `false`.\n *\n * This lives in `@takuhon/core` because it is a pure transform over the core\n * document types with no transport coupling, so every public surface — the\n * API layer, the CLI's `build`, future renderers — applies the exact same\n * projection. `@takuhon/api` re-exports it for backwards compatibility.\n *\n * Fields filtered:\n *\n * - `certifications[*].credentialId` — hidden when\n * `meta.privacy.hideCredentialIds !== false` (default true).\n * - `education[*].grade` — hidden when\n * `meta.privacy.hideEducationGrades !== false` (default true).\n * - `contact.email` — hidden when `contact.showEmail !== true`.\n *\n * `patents[*].patentNumber` is **not** filtered. Patent numbers are public\n * records (issued patents are published by the granting office) and Spec\n * §6.21 explicitly excludes them from the privacy block.\n *\n * Behavior:\n *\n * - Pure function. The input is never mutated; a shallow-copied result is\n * returned with only the touched arrays / objects replaced.\n * - When no filter applies (every flag opts into disclosure), the original\n * reference is returned as-is so callers can compare by identity.\n * - Admin endpoints (`/api/admin/*`, including `/api/admin/export`) MUST NOT\n * call this helper — they always serve the full document to authenticated\n * callers.\n */\n\nimport type { LocalizedTakuhon, Takuhon } from './types.js';\n\n/**\n * Union of the two profile shapes that traverse the public path. The fields\n * the filter touches (`certifications[*].credentialId`, `education[*].grade`,\n * `contact.email`) are structurally identical between {@link Takuhon} and\n * {@link LocalizedTakuhon}, so the same logic applies to either shape.\n */\ntype FilterableProfile = Takuhon | LocalizedTakuhon;\n\n/**\n * Return a privacy-filtered copy of `profile` suitable for public responses.\n *\n * @param profile Either a raw {@link Takuhon} or a locale-resolved\n * {@link LocalizedTakuhon}. The output preserves the input's\n * exact shape.\n */\nexport function applyPublicPrivacyFilter<T extends FilterableProfile>(profile: T): T {\n const hideCredentialIds = profile.meta.privacy?.hideCredentialIds !== false;\n const hideEducationGrades = profile.meta.privacy?.hideEducationGrades !== false;\n const allowEmail = profile.contact.showEmail === true;\n\n const stripCertifications = hideCredentialIds && hasAnyCredentialId(profile);\n const stripEducation = hideEducationGrades && hasAnyGrade(profile);\n const stripEmail = !allowEmail && profile.contact.email !== undefined;\n\n if (!stripCertifications && !stripEducation && !stripEmail) {\n return profile;\n }\n\n const out: FilterableProfile = { ...profile };\n\n if (stripCertifications) {\n out.certifications = profile.certifications.map(stripCredentialId) as T['certifications'];\n }\n\n if (stripEducation) {\n out.education = profile.education.map(stripGrade) as T['education'];\n }\n\n if (stripEmail) {\n const { email: _omit, ...rest } = profile.contact;\n out.contact = rest;\n }\n\n return out as T;\n}\n\nfunction hasAnyCredentialId(profile: FilterableProfile): boolean {\n return profile.certifications.some((c) => c.credentialId !== undefined);\n}\n\nfunction hasAnyGrade(profile: FilterableProfile): boolean {\n return profile.education.some((e) => e.grade !== undefined);\n}\n\nfunction stripCredentialId<T extends { credentialId?: string }>(item: T): T {\n if (item.credentialId === undefined) return item;\n const { credentialId: _omit, ...rest } = item;\n return rest as T;\n}\n\nfunction stripGrade<T extends { grade?: string }>(item: T): T {\n if (item.grade === undefined) return item;\n const { grade: _omit, ...rest } = item;\n return rest as T;\n}\n","/**\n * Module-private chain-building helper for the migration registry.\n *\n * Not re-exported from `@takuhon/core`'s public surface: the algorithm is an\n * implementation detail of {@link migrateTakuhon}, and adding it to the\n * public API would freeze its signature under semver. Unit tests import\n * this file directly to exercise the chain logic against synthetic\n * fixtures.\n */\n\nimport type { Takuhon } from '../types.js';\n\nimport type { Migration } from './index.js';\n\n/**\n * Build a forward chain of migrations from `from` to `to`. Returns `[]`\n * when `from === to`, or `null` when no chain exists or a cycle is\n * encountered. The walk is linear (one outgoing edge per `from`); a\n * visited-set guards against cycles introduced by misconfigured registries.\n */\nexport function findMigrationChain(\n from: string,\n to: string,\n registry: readonly Migration<Takuhon, Takuhon>[],\n): Migration<Takuhon, Takuhon>[] | null {\n if (from === to) return [];\n const byFrom = new Map<string, Migration<Takuhon, Takuhon>>();\n for (const m of registry) byFrom.set(m.from, m);\n const chain: Migration<Takuhon, Takuhon>[] = [];\n const visited = new Set<string>([from]);\n let cur = from;\n while (cur !== to) {\n const next = byFrom.get(cur);\n if (!next) return null;\n if (visited.has(next.to)) return null;\n chain.push(next);\n visited.add(next.to);\n cur = next.to;\n }\n return chain;\n}\n","/**\n * Forward migration from schema 0.1.0 to 0.2.0.\n *\n * Adds nine new top-level array fields (`certifications` / `memberships` /\n * `volunteering` / `honors` / `education` / `publications` / `languages` /\n * `courses` / `patents`) and the `meta.privacy` opt-out block. The\n * transformation is additive: existing fields pass through untouched and no\n * 0.1.x value is dropped.\n *\n * Conditional spread is intentional. The 0.1.x schema closes the document\n * root (`additionalProperties: false`), so a validated 0.1.x profile cannot\n * carry pre-existing values at the new keys. The migration nevertheless\n * runs on `unknown`-shaped input that may not have been validated yet — a\n * stored profile authored ahead of time with forward-compatible 0.2.0 keys,\n * an import file from a downstream consumer, etc. Preserving any value\n * already present at these keys prevents data loss in those paths.\n */\n\nimport type { Takuhon } from '../types.js';\n\nimport type { Migration } from './index.js';\n\nexport const v0_1_0_to_v0_2_0: Migration<Takuhon, Takuhon> = {\n from: '0.1.0',\n to: '0.2.0',\n migrate(data: Takuhon): Takuhon {\n const partial = data as Partial<Takuhon>;\n return {\n ...data,\n schemaVersion: '0.2.0',\n certifications: partial.certifications ?? [],\n memberships: partial.memberships ?? [],\n volunteering: partial.volunteering ?? [],\n honors: partial.honors ?? [],\n education: partial.education ?? [],\n publications: partial.publications ?? [],\n languages: partial.languages ?? [],\n courses: partial.courses ?? [],\n patents: partial.patents ?? [],\n };\n },\n};\n","/**\n * Forward migration from schema 0.2.0 to 0.3.0.\n *\n * Adds the `testScores` top-level array (standardized test / exam scores,\n * LinkedIn `Test_Scores.csv` equivalent). The transformation is additive:\n * existing fields pass through untouched and no 0.2.x value is dropped.\n *\n * Conditional spread mirrors `v0.1.0-to-v0.2.0`. The 0.2.x schema closes the\n * document root (`additionalProperties: false`), so a validated 0.2.x profile\n * cannot carry a pre-existing `testScores` value. The migration nevertheless\n * runs on `unknown`-shaped input that may not have been validated yet — a\n * stored profile authored ahead of time with a forward-compatible 0.3.0 key,\n * an import file from a downstream consumer, etc. Preserving any value already\n * present at `testScores` prevents data loss in those paths.\n */\n\nimport type { Takuhon } from '../types.js';\n\nimport type { Migration } from './index.js';\n\nexport const v0_2_0_to_v0_3_0: Migration<Takuhon, Takuhon> = {\n from: '0.2.0',\n to: '0.3.0',\n migrate(data: Takuhon): Takuhon {\n const partial = data as Partial<Takuhon>;\n return {\n ...data,\n schemaVersion: '0.3.0',\n testScores: partial.testScores ?? [],\n };\n },\n};\n","/**\n * Forward migration from schema 0.3.0 to 0.4.0.\n *\n * Adds the `recommendations` top-level array (owner-curated testimonials, the\n * LinkedIn `Recommendations_Received.csv` equivalent). The transformation is\n * additive: existing fields pass through untouched and no 0.3.x value is\n * dropped.\n *\n * Conditional spread mirrors the earlier migrations. The 0.3.x schema closes\n * the document root (`additionalProperties: false`), so a validated 0.3.x\n * profile cannot carry a pre-existing `recommendations` value. The migration\n * nevertheless runs on `unknown`-shaped input that may not have been validated\n * yet — a stored profile authored ahead of time with a forward-compatible\n * 0.4.0 key, an import file from a downstream consumer, etc. Preserving any\n * value already present at `recommendations` prevents data loss in those paths.\n */\n\nimport type { Takuhon } from '../types.js';\n\nimport type { Migration } from './index.js';\n\nexport const v0_3_0_to_v0_4_0: Migration<Takuhon, Takuhon> = {\n from: '0.3.0',\n to: '0.4.0',\n migrate(data: Takuhon): Takuhon {\n const partial = data as Partial<Takuhon>;\n return {\n ...data,\n schemaVersion: '0.4.0',\n recommendations: partial.recommendations ?? [],\n };\n },\n};\n","/**\n * Forward migration registry for `@takuhon/core`.\n *\n * Each migration is a pure function from a takuhon document at version `from`\n * to one at version `to`. The registry is consulted by {@link migrateTakuhon}\n * to build a chain when the requested target is more than one step away\n * (`0.1.0 → 0.3.0` is composed of `0.1.0→0.2.0` and `0.2.0→0.3.0`).\n *\n * Authoring conventions:\n * - File name: `vX.Y.Z-to-vA.B.C.ts`\n * - Pure function: must not mutate input, must not perform I/O\n * - Forward only: downgrades are not provided; recovery is via the backup\n * restore path (operational-lifecycle §4)\n * - Each entry ships with a unit test: sample input/output, idempotency\n * when applicable, and schema-pass against the target version's schema\n *\n * The chain-building algorithm lives in `_chain.ts` and is intentionally\n * not re-exported from `@takuhon/core` — it is an implementation detail of\n * {@link migrateTakuhon}.\n */\n\nimport type { Takuhon } from '../types.js';\n\nimport { v0_1_0_to_v0_2_0 } from './v0.1.0-to-v0.2.0.js';\nimport { v0_2_0_to_v0_3_0 } from './v0.2.0-to-v0.3.0.js';\nimport { v0_3_0_to_v0_4_0 } from './v0.3.0-to-v0.4.0.js';\n\n/**\n * A forward migration entry. `from` and `to` are semver strings matching\n * the `schemaVersion` field of the input and output documents. `migrate`\n * is pure: it must not mutate `data`.\n */\nexport interface Migration<From, To> {\n from: string;\n to: string;\n migrate(data: From): To;\n}\n\n/**\n * Forward migrations bundled with this build of `@takuhon/core`.\n *\n * Entries are listed in the order they would chain for forward migration\n * (`0.1.0 → 0.2.0 → 0.3.0 → ...`). {@link migrateTakuhon} consults this\n * array to build the chain between a source `schemaVersion` and a target.\n */\nexport const migrations: readonly Migration<Takuhon, Takuhon>[] = [\n v0_1_0_to_v0_2_0,\n v0_2_0_to_v0_3_0,\n v0_3_0_to_v0_4_0,\n];\n","/**\n * Forward migration entry point for takuhon documents.\n *\n * {@link migrateTakuhon} composes a chain of {@link Migration} entries from\n * the registry (`./migrations`) and applies them in order. The registry\n * currently ships the `0.1.0 → 0.2.0`, `0.2.0 → 0.3.0`, and `0.3.0 → 0.4.0`\n * forward migrations; a request whose source has no chain to the target\n * throws {@link MigrationError}.\n *\n * Scope (deliberately narrow, mirroring `export.ts`):\n * - Pure data transform — no I/O, no backup creation, no storage write.\n * - Backup-before-migrate (operational-lifecycle §3.1) is the storage /\n * API layer's responsibility; this function only transforms the\n * in-memory document.\n * - Forward only (operational-lifecycle §2.4); downgrade is via restore.\n */\n\nimport { findMigrationChain } from './migrations/_chain.js';\nimport { migrations } from './migrations/index.js';\nimport type { Takuhon } from './types.js';\n\n/**\n * Thrown by {@link migrateTakuhon} when no forward chain connects the\n * source `schemaVersion` to `targetVersion`. The message includes both\n * versions so the API layer can surface an actionable RFC 7807 problem.\n */\nexport class MigrationError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = 'MigrationError';\n }\n}\n\n/**\n * Migrate a takuhon document forward to `targetVersion`. Returns a deep\n * clone; the input is never mutated, even when a migration throws.\n *\n * @throws {MigrationError} when no forward chain exists from\n * `data.schemaVersion` to `targetVersion`.\n */\nexport function migrateTakuhon(data: Takuhon, targetVersion: string): Takuhon {\n const sourceVersion = data.schemaVersion;\n if (sourceVersion === targetVersion) {\n return JSON.parse(JSON.stringify(data)) as Takuhon;\n }\n const chain = findMigrationChain(sourceVersion, targetVersion, migrations);\n if (!chain) {\n throw new MigrationError(`No migration path from ${sourceVersion} to ${targetVersion}`);\n }\n let current: Takuhon = JSON.parse(JSON.stringify(data)) as Takuhon;\n for (const step of chain) {\n current = step.migrate(current);\n }\n return current;\n}\n","/**\n * Persistence contracts for takuhon profile documents and binary assets.\n *\n * Adapters (KV / R2 / filesystem / SQLite / …) implement these interfaces to\n * plug into `@takuhon/api`. All methods are async; failures surface as\n * exceptions in the {@link StorageError} family so the API layer can map them\n * onto RFC 7807 problem details.\n *\n * Design notes:\n * - `version` is an opaque ETag-like token (UUID, hash, monotonic counter —\n * the adapter chooses). It powers HTTP `If-Match` style optimistic locking\n * and is unrelated to {@link Takuhon.schemaVersion}, which describes the\n * document's data-model version.\n * - `getProfile()` returns a raw {@link Takuhon}, not a normalized or\n * locale-resolved one. Normalization and locale resolution belong to the\n * API / render layer; storage only persists.\n * - `saveProfile(data, ifMatch?)` rejects with {@link ConflictError} when\n * `ifMatch` is supplied and does not equal the current stored version.\n * When `ifMatch` is omitted, the adapter's policy decides whether to\n * overwrite unconditionally; per-implementation docs spell this out.\n * - `TakuhonAssetStorage` is intentionally a separate interface so deployments\n * that don't host user-uploaded media (e.g. static export) can omit it.\n * - The naming standardises on the lowercase \"Takuhon\" word (cf.\n * {@link Takuhon}, {@link LocalizedTakuhon}, `normalize`, `validate`) even\n * where upstream documents write \"Takuhon\".\n */\n\nimport type { Takuhon } from './types.js';\n\n/**\n * Persistence contract for the single profile document of a takuhon instance.\n *\n * Implementations: Cloudflare KV (Phase 3), filesystem (Phase 3+), in-memory\n * test doubles, and future SQL adapters.\n */\nexport interface TakuhonStorage {\n /**\n * Read the current profile document and its opaque version token.\n *\n * @throws {NotFoundError} when no profile has been saved yet.\n */\n getProfile(): Promise<{ data: Takuhon; version: string }>;\n\n /**\n * Replace the profile document. The returned `version` is the new opaque\n * token to supply as the next `ifMatch`.\n *\n * @param data the document to persist (raw, not normalized)\n * @param ifMatch when set, the adapter rejects the write unless the\n * current stored version equals this token\n * @throws {ConflictError} when `ifMatch` is supplied and does not equal\n * the current stored version\n */\n saveProfile(data: Takuhon, ifMatch?: string): Promise<{ version: string }>;\n\n /**\n * Remove the profile document. Idempotent: no error when nothing is stored.\n */\n deleteProfile(): Promise<void>;\n}\n\n/**\n * Metadata for a stored binary asset, returned by {@link TakuhonAssetStorage}.\n *\n * `url` is the relative path used inside the document (`/assets/...`);\n * `publicUrl` is the absolute URL a browser can fetch. The two are kept\n * distinct because adapters may serve assets from a different host than the\n * profile (e.g. Cloudflare R2 + custom CDN).\n */\nexport interface AssetRecord {\n id: string;\n url: string;\n publicUrl: string;\n mimeType: string;\n size: number;\n width?: number;\n height?: number;\n /** ISO-8601 timestamp. */\n createdAt?: string;\n}\n\n/**\n * Caller hints for {@link TakuhonAssetStorage.putAsset}. Both fields are\n * optional; when omitted, the adapter falls back to the `File` / `Blob`\n * metadata. Adapters are responsible for magic-byte verification, EXIF\n * stripping, and dimension limits — callers must not pre-process.\n */\nexport interface AssetOptions {\n filename?: string;\n contentType?: string;\n}\n\n/**\n * Persistence contract for binary assets (avatars, project images, …).\n *\n * `listAssets()` is unbounded by design for the MVP; later phases may\n * introduce paginated semantics with a different return shape. `getPublicUrl()`\n * takes only an `assetId` today; a future options object (e.g. `expiresIn`\n * for signed URLs) would be added in a backward-compatible way.\n */\nexport interface TakuhonAssetStorage {\n putAsset(file: File | Blob, options?: AssetOptions): Promise<AssetRecord>;\n /** @throws {NotFoundError} when no asset exists for `assetId`. */\n getPublicUrl(assetId: string): Promise<string>;\n /** Idempotent: no error when the asset is already absent. */\n deleteAsset(assetId: string): Promise<void>;\n listAssets(): Promise<AssetRecord[]>;\n}\n\n/**\n * Base class for errors thrown by storage adapters. Catch this to handle\n * any storage-layer failure uniformly; check `instanceof` of a subclass\n * (e.g. {@link NotFoundError}, {@link ConflictError}) to discriminate.\n */\nexport class StorageError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = 'StorageError';\n }\n}\n\n/** Thrown when a requested resource (profile or asset) does not exist. */\nexport class NotFoundError extends StorageError {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = 'NotFoundError';\n }\n}\n\n/**\n * Thrown when an optimistic-locking precondition fails: the caller supplied\n * an `ifMatch` token that does not equal the current stored version.\n *\n * `currentVersion` (when set) carries the actual current version so the\n * caller can decide between refetch-and-retry and surfacing a 409 to the\n * end user without an extra round trip.\n */\nexport class ConflictError extends StorageError {\n readonly currentVersion?: string;\n\n constructor(message: string, options?: { currentVersion?: string; cause?: unknown }) {\n super(message, { cause: options?.cause });\n this.name = 'ConflictError';\n this.currentVersion = options?.currentVersion;\n }\n}\n","/**\n * @takuhon/core — canonical JSON Schema, hand-written TypeScript types,\n * Ajv-backed validation, document normalization, and locale resolution for\n * takuhon profile data.\n *\n * Public surface (Phase 1):\n * - {@link schema}: the JSON Schema 2020-12 contract bundled with this build.\n * - {@link SCHEMA_VERSION}: the version of that schema (matches the `$id`).\n * - {@link validate} / {@link ValidationResult} / {@link ValidationError} /\n * {@link SUPPORTED_SCHEMA_VERSIONS}: Result-style validator backed by Ajv.\n * - {@link normalize} / {@link NormalizedTakuhon}: canonicalize a validated\n * document (sort lists by `order`, drop blank localized entries).\n * - {@link resolveLocale} / {@link LocalizedTakuhon}: collapse a multi-locale\n * document to a single requested locale with BCP-47 regional fallback.\n * - {@link generateJsonLd} / {@link generatePersonJsonLd} /\n * {@link generateProfilePageJsonLd}: emit Schema.org JSON-LD\n * (`ProfilePage` wrapping `Person`) from a locale-resolved document.\n * - {@link TakuhonStorage} / {@link TakuhonAssetStorage}: persistence contracts\n * for adapters (KV / R2 / filesystem / SQLite / …), with the\n * {@link StorageError} / {@link NotFoundError} / {@link ConflictError}\n * exception family for optimistic-locking and not-found signalling.\n * - {@link exportTakuhon} / {@link importTakuhon} / {@link ExportOptions} /\n * {@link ExportedTakuhon} / {@link ImportError}: roundtrip-stable\n * serialisation for transport (file, API response, …).\n * - {@link migrateTakuhon} / {@link Migration} / {@link migrations} /\n * {@link MigrationError}: forward-only migration registry, chaining\n * `0.1.0 → 0.2.0 → 0.3.0 → 0.4.0`.\n * - Domain types: {@link Takuhon} and its constituent shapes (`Profile`,\n * `Settings`, `Career`, `Project`, `Link` discriminated union, etc.).\n */\n\nexport { schema } from './schema.js';\nexport type { Schema } from './schema.js';\n\nexport { SUPPORTED_SCHEMA_VERSIONS, validate } from './validate.js';\nexport type { ValidationError, ValidationResult } from './validate.js';\n\nexport { normalize } from './normalize.js';\nexport { resolveLocale } from './resolve-locale.js';\nexport { generateJsonLd, generatePersonJsonLd, generateProfilePageJsonLd } from './jsonld.js';\n\nexport { ImportError, exportTakuhon, importTakuhon } from './export.js';\nexport type { ExportOptions, ExportedTakuhon } from './export.js';\n\nexport { applyPublicPrivacyFilter } from './privacy-filter.js';\n\nexport { MigrationError, migrateTakuhon } from './migrate.js';\nexport { migrations } from './migrations/index.js';\nexport type { Migration } from './migrations/index.js';\n\nexport { ConflictError, NotFoundError, StorageError } from './storage-interface.js';\nexport type {\n AssetOptions,\n AssetRecord,\n TakuhonAssetStorage,\n TakuhonStorage,\n} from './storage-interface.js';\n\nexport type {\n Address,\n Avatar,\n Career,\n Certification,\n Contact,\n ContentLicense,\n ContentLicenseAttribution,\n Course,\n Education,\n Honor,\n Iso3166Alpha2,\n IsoDateTime,\n Language,\n LanguageProficiency,\n Link,\n LinkBuiltin,\n LinkCustom,\n LinkType,\n LocaleTag,\n LocalizedAddress,\n LocalizedAvatar,\n LocalizedBody,\n LocalizedCareer,\n LocalizedCertification,\n LocalizedCourse,\n LocalizedEducation,\n LocalizedHonor,\n LocalizedLanguage,\n LocalizedLink,\n LocalizedLinkBuiltin,\n LocalizedLinkCustom,\n LocalizedMembership,\n LocalizedPatent,\n LocalizedProfile,\n LocalizedProject,\n LocalizedPublication,\n LocalizedRecommendation,\n LocalizedRecommendationAuthor,\n LocalizedTakuhon,\n LocalizedTestScore,\n LocalizedTitle,\n LocalizedVolunteering,\n Membership,\n Meta,\n MetaPrivacy,\n NormalizedTakuhon,\n Patent,\n PatentStatus,\n Profile,\n Project,\n Publication,\n Recommendation,\n RecommendationAuthor,\n Settings,\n Skill,\n Slug,\n Takuhon,\n TestScore,\n Volunteering,\n YearMonth,\n} from './types.js';\n\n/**\n * Version of the takuhon schema bundled with this build of `@takuhon/core`.\n * A takuhon profile document's `schemaVersion` field must be migrate-compatible\n * with this version. See operational-lifecycle docs for the migration policy.\n */\nexport const SCHEMA_VERSION = '0.4.0';\n"],"mappings":"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","names":["out"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takuhon/core",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "JSON Schema, validation, normalization, locale resolution, and JSON-LD generation for takuhon",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Takuhon contributors",