@takuhon/core 1.0.0 → 1.3.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
@@ -1,5 +1,5 @@
1
1
  var $schema = "https://json-schema.org/draft/2020-12/schema";
2
- var $id = "https://takuhon.example/schemas/1.0.0/takuhon.schema.json";
2
+ var $id = "https://takuhon.example/schemas/1.3.0/takuhon.schema.json";
3
3
  var title = "Takuhon Profile";
4
4
  var description = "Portable profile data format consumed by @takuhon/core. The canonical contract for profile content authored as takuhon.json.";
5
5
  var type = "object";
@@ -496,6 +496,26 @@ var $defs = {
496
496
  }
497
497
  }
498
498
  },
499
+ SkillCategory: {
500
+ type: "object",
501
+ additionalProperties: false,
502
+ required: [
503
+ "id",
504
+ "label"
505
+ ],
506
+ properties: {
507
+ id: {
508
+ type: "string",
509
+ minLength: 1,
510
+ maxLength: 64,
511
+ description: "Matches the `category` value on the skills that belong to this group."
512
+ },
513
+ label: {
514
+ $ref: "#/$defs/LocalizedTitle",
515
+ description: "Localized display heading for the group."
516
+ }
517
+ }
518
+ },
499
519
  Contact: {
500
520
  type: "object",
501
521
  additionalProperties: false,
@@ -566,6 +586,118 @@ var $defs = {
566
586
  },
567
587
  publicVisibility: {
568
588
  $ref: "#/$defs/PublicVisibility"
589
+ },
590
+ contact: {
591
+ $ref: "#/$defs/ContactSettings"
592
+ },
593
+ appearance: {
594
+ $ref: "#/$defs/AppearanceSettings"
595
+ },
596
+ skillCategories: {
597
+ type: "array",
598
+ maxItems: 50,
599
+ items: {
600
+ $ref: "#/$defs/SkillCategory"
601
+ },
602
+ description: "Ordered skill-category display groups (added in 1.3.0). When present, the rendered profile groups skills by their `category` under these localized headings, in array order; absent = the flat skill list. A skill whose `category` is not listed here (or which has none) renders in a trailing group so nothing is dropped."
603
+ }
604
+ }
605
+ },
606
+ AppearanceSettings: {
607
+ type: "object",
608
+ additionalProperties: false,
609
+ description: "Opt-in design tokens for the rendered profile (added in 1.2.0). A declarative re-skin seam: owners override the standard renderer's built-in color and font defaults. This is a token map only, not arbitrary CSS — every value is length- and pattern-constrained so it cannot break out of the inline <style>. Overriding tokens re-skins the page but cannot re-layout it (spacing/radius/type-scale are intentionally not exposed). Absent = the built-in defaults are used unchanged.",
610
+ properties: {
611
+ fontFamily: {
612
+ type: "string",
613
+ minLength: 1,
614
+ maxLength: 256,
615
+ pattern: "^[A-Za-z0-9\\s,'\"._-]+$",
616
+ description: "CSS font-family stack for the page body, e.g. \"Inter, system-ui, sans-serif\". Quotes and commas are allowed; CSS-structural characters (; { } < >) are not."
617
+ },
618
+ colors: {
619
+ $ref: "#/$defs/AppearanceColors",
620
+ description: "Light-mode (:root) color overrides."
621
+ },
622
+ colorsDark: {
623
+ $ref: "#/$defs/AppearanceColors",
624
+ description: "Dark-mode (prefers-color-scheme: dark) color overrides. Note: until the standard renderer ships a default dark palette, only the keys set here change in dark mode."
625
+ }
626
+ }
627
+ },
628
+ AppearanceColors: {
629
+ type: "object",
630
+ additionalProperties: false,
631
+ description: "A set of overridable color tokens. Each value is a CSS color (hex, rgb()/rgba(), hsl()/hsla(), or a named color); CSS-structural characters (; { } < > \" ' \\) are disallowed so a value cannot escape the inline <style>.",
632
+ properties: {
633
+ bg: {
634
+ $ref: "#/$defs/CssColor",
635
+ description: "Page background."
636
+ },
637
+ surface: {
638
+ $ref: "#/$defs/CssColor",
639
+ description: "Raised surfaces such as skill/tag chips."
640
+ },
641
+ text: {
642
+ $ref: "#/$defs/CssColor",
643
+ description: "Primary body text."
644
+ },
645
+ textMuted: {
646
+ $ref: "#/$defs/CssColor",
647
+ description: "Secondary/muted text (taglines, meta, captions)."
648
+ },
649
+ border: {
650
+ $ref: "#/$defs/CssColor",
651
+ description: "Hairline borders and rules."
652
+ },
653
+ accent: {
654
+ $ref: "#/$defs/CssColor",
655
+ description: "Accent color for emphasis and focus affordances."
656
+ },
657
+ primary: {
658
+ $ref: "#/$defs/CssColor",
659
+ description: "Primary interactive color, e.g. links."
660
+ },
661
+ primaryContrast: {
662
+ $ref: "#/$defs/CssColor",
663
+ description: "Foreground color used on top of the primary color."
664
+ }
665
+ }
666
+ },
667
+ CssColor: {
668
+ type: "string",
669
+ minLength: 1,
670
+ maxLength: 64,
671
+ pattern: "^(?:#[0-9A-Fa-f]{3,8}|[A-Za-z]+|(?:rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch|color)\\([A-Za-z0-9.,%/\\s-]*\\))$",
672
+ description: "A CSS color value, restricted to a safe allowlist: a hex color (#rgb/#rgba/#rrggbb/#rrggbbaa), a bare keyword (named colors, currentColor, transparent), or a color function (rgb/rgba/hsl/hsla/hwb/lab/lch/oklab/oklch/color). url(), image-set(), var(), and other fetch- or reference-bearing functions are intentionally excluded so a value can never trigger an external request or escape the inline <style>."
673
+ },
674
+ ContactSettings: {
675
+ type: "object",
676
+ additionalProperties: false,
677
+ description: "Opt-in contact form configuration (added in 1.1.0). Only public values live here; the Turnstile site key is safe to embed in the page. The Turnstile secret, the recipient address, and the From label are provisioned out of band as environment configuration and are never stored in takuhon.json. Adapters that support the form mount the widget and a POST endpoint when 'enabled' is true.",
678
+ properties: {
679
+ enabled: {
680
+ type: "boolean",
681
+ "default": false,
682
+ description: "Master switch. When false (the default), no contact form is mounted even if a site key is present."
683
+ },
684
+ turnstileSiteKey: {
685
+ type: "string",
686
+ minLength: 1,
687
+ maxLength: 128,
688
+ description: "Public Cloudflare Turnstile site key, safe to embed in the page. Without it the widget is not mounted."
689
+ },
690
+ endpoint: {
691
+ type: "string",
692
+ minLength: 1,
693
+ maxLength: 2048,
694
+ description: "Override the POST endpoint the widget submits to. Defaults to /api/contact on the same origin."
695
+ },
696
+ subjectPrefix: {
697
+ type: "string",
698
+ minLength: 1,
699
+ maxLength: 128,
700
+ description: "Subject prefix for the delivered email, e.g. '[example.com contact]'."
569
701
  }
570
702
  }
571
703
  },
@@ -1814,6 +1946,23 @@ declare const schema: {
1814
1946
  };
1815
1947
  };
1816
1948
  };
1949
+ SkillCategory: {
1950
+ type: string;
1951
+ additionalProperties: boolean;
1952
+ required: string[];
1953
+ properties: {
1954
+ id: {
1955
+ type: string;
1956
+ minLength: number;
1957
+ maxLength: number;
1958
+ description: string;
1959
+ };
1960
+ label: {
1961
+ $ref: string;
1962
+ description: string;
1963
+ };
1964
+ };
1965
+ };
1817
1966
  Contact: {
1818
1967
  type: string;
1819
1968
  additionalProperties: boolean;
@@ -1882,6 +2031,118 @@ declare const schema: {
1882
2031
  publicVisibility: {
1883
2032
  $ref: string;
1884
2033
  };
2034
+ contact: {
2035
+ $ref: string;
2036
+ };
2037
+ appearance: {
2038
+ $ref: string;
2039
+ };
2040
+ skillCategories: {
2041
+ type: string;
2042
+ maxItems: number;
2043
+ items: {
2044
+ $ref: string;
2045
+ };
2046
+ description: string;
2047
+ };
2048
+ };
2049
+ };
2050
+ AppearanceSettings: {
2051
+ type: string;
2052
+ additionalProperties: boolean;
2053
+ description: string;
2054
+ properties: {
2055
+ fontFamily: {
2056
+ type: string;
2057
+ minLength: number;
2058
+ maxLength: number;
2059
+ pattern: string;
2060
+ description: string;
2061
+ };
2062
+ colors: {
2063
+ $ref: string;
2064
+ description: string;
2065
+ };
2066
+ colorsDark: {
2067
+ $ref: string;
2068
+ description: string;
2069
+ };
2070
+ };
2071
+ };
2072
+ AppearanceColors: {
2073
+ type: string;
2074
+ additionalProperties: boolean;
2075
+ description: string;
2076
+ properties: {
2077
+ bg: {
2078
+ $ref: string;
2079
+ description: string;
2080
+ };
2081
+ surface: {
2082
+ $ref: string;
2083
+ description: string;
2084
+ };
2085
+ text: {
2086
+ $ref: string;
2087
+ description: string;
2088
+ };
2089
+ textMuted: {
2090
+ $ref: string;
2091
+ description: string;
2092
+ };
2093
+ border: {
2094
+ $ref: string;
2095
+ description: string;
2096
+ };
2097
+ accent: {
2098
+ $ref: string;
2099
+ description: string;
2100
+ };
2101
+ primary: {
2102
+ $ref: string;
2103
+ description: string;
2104
+ };
2105
+ primaryContrast: {
2106
+ $ref: string;
2107
+ description: string;
2108
+ };
2109
+ };
2110
+ };
2111
+ CssColor: {
2112
+ type: string;
2113
+ minLength: number;
2114
+ maxLength: number;
2115
+ pattern: string;
2116
+ description: string;
2117
+ };
2118
+ ContactSettings: {
2119
+ type: string;
2120
+ additionalProperties: boolean;
2121
+ description: string;
2122
+ properties: {
2123
+ enabled: {
2124
+ type: string;
2125
+ default: boolean;
2126
+ description: string;
2127
+ };
2128
+ turnstileSiteKey: {
2129
+ type: string;
2130
+ minLength: number;
2131
+ maxLength: number;
2132
+ description: string;
2133
+ };
2134
+ endpoint: {
2135
+ type: string;
2136
+ minLength: number;
2137
+ maxLength: number;
2138
+ description: string;
2139
+ };
2140
+ subjectPrefix: {
2141
+ type: string;
2142
+ minLength: number;
2143
+ maxLength: number;
2144
+ description: string;
2145
+ };
1885
2146
  };
1886
2147
  };
1887
2148
  PublicVisibility: {
@@ -2921,6 +3182,91 @@ interface Settings {
2921
3182
  activity?: ActivitySettings;
2922
3183
  /** Per-section public visibility (added in 0.6.0). Absent = all sections visible. */
2923
3184
  publicVisibility?: PublicVisibility;
3185
+ /** Opt-in contact form (added in 1.1.0). Absent = no contact form. */
3186
+ contact?: ContactSettings;
3187
+ /** Opt-in design tokens for the rendered profile (added in 1.2.0). Absent = built-in defaults. */
3188
+ appearance?: AppearanceSettings;
3189
+ /**
3190
+ * Ordered skill-category display groups (added in 1.3.0). When present, the
3191
+ * rendered profile groups skills by their `category` under these localized
3192
+ * headings, in array order; absent = the flat skill list. A skill whose
3193
+ * `category` is unlisted (or absent) renders in a trailing group.
3194
+ */
3195
+ skillCategories?: SkillCategory[];
3196
+ }
3197
+ /**
3198
+ * One skill-category display group (added in 1.3.0). Maps a `Skill.category`
3199
+ * value to a localized heading; the array position in {@link
3200
+ * Settings.skillCategories} defines the group's display order.
3201
+ */
3202
+ interface SkillCategory {
3203
+ /** Matches the `category` value on the skills that belong to this group. */
3204
+ id: string;
3205
+ /** Localized display heading for the group. */
3206
+ label: LocalizedTitle;
3207
+ }
3208
+ /**
3209
+ * Opt-in design tokens for the rendered profile (added in 1.2.0).
3210
+ *
3211
+ * A declarative re-skin seam: owners override the standard renderer's built-in
3212
+ * color and font defaults. This is a token map only — never arbitrary CSS — so
3213
+ * every value is length- and pattern-constrained (see the schema) and cannot
3214
+ * break out of the inline `<style>`. Overriding tokens re-skins the page but
3215
+ * cannot re-layout it; spacing, radius, and the type scale are intentionally
3216
+ * not exposed. An absent block leaves the built-in defaults unchanged.
3217
+ */
3218
+ interface AppearanceSettings {
3219
+ /** CSS font-family stack for the page body, e.g. `"Inter, system-ui, sans-serif"`. */
3220
+ fontFamily?: string;
3221
+ /** Light-mode (`:root`) color overrides. */
3222
+ colors?: AppearanceColors;
3223
+ /**
3224
+ * Dark-mode (`prefers-color-scheme: dark`) color overrides. Until the
3225
+ * standard renderer ships a default dark palette, only the keys set here
3226
+ * change in dark mode.
3227
+ */
3228
+ colorsDark?: AppearanceColors;
3229
+ }
3230
+ /**
3231
+ * Overridable color tokens (added in 1.2.0). Each value is a CSS color (hex,
3232
+ * `rgb()`/`rgba()`, `hsl()`/`hsla()`, or a named color); CSS-structural
3233
+ * characters are disallowed so a value cannot escape the inline `<style>`.
3234
+ */
3235
+ interface AppearanceColors {
3236
+ /** Page background. */
3237
+ bg?: string;
3238
+ /** Raised surfaces such as skill/tag chips. */
3239
+ surface?: string;
3240
+ /** Primary body text. */
3241
+ text?: string;
3242
+ /** Secondary/muted text (taglines, meta, captions). */
3243
+ textMuted?: string;
3244
+ /** Hairline borders and rules. */
3245
+ border?: string;
3246
+ /** Accent color for emphasis and focus affordances. */
3247
+ accent?: string;
3248
+ /** Primary interactive color, e.g. links. */
3249
+ primary?: string;
3250
+ /** Foreground color used on top of the primary color. */
3251
+ primaryContrast?: string;
3252
+ }
3253
+ /**
3254
+ * Owner-curated configuration for the opt-in contact form (added in 1.1.0).
3255
+ * Only public values live here: the Turnstile **site key** is safe to embed in
3256
+ * the page. The Turnstile secret, the recipient address, and the From label are
3257
+ * provisioned out of band as environment configuration and are never stored in
3258
+ * `takuhon.json`. Adapters that support the form mount the widget and a POST
3259
+ * endpoint when {@link enabled} is true; adapters that do not simply ignore it.
3260
+ */
3261
+ interface ContactSettings {
3262
+ /** Master switch; no contact form is mounted when false (the default). */
3263
+ enabled?: boolean;
3264
+ /** Public Cloudflare Turnstile site key, safe to embed; required to mount the widget. */
3265
+ turnstileSiteKey?: string;
3266
+ /** Override the POST endpoint the widget submits to. Defaults to `/api/contact` (same origin). */
3267
+ endpoint?: string;
3268
+ /** Subject prefix for the delivered email, e.g. `"[example.com contact]"`. */
3269
+ subjectPrefix?: string;
2924
3270
  }
2925
3271
  /**
2926
3272
  * Per-section public/private visibility (added in 0.6.0).
@@ -3253,13 +3599,31 @@ interface LocalizedRecommendation extends VisibilityControlled {
3253
3599
  relatedEducationId?: Slug;
3254
3600
  order?: number;
3255
3601
  }
3602
+ /**
3603
+ * One skill-category group after locale resolution: the localized `label` map
3604
+ * collapsed to the single resolved string. See {@link SkillCategory}.
3605
+ */
3606
+ interface LocalizedSkillCategory {
3607
+ id: string;
3608
+ label: string;
3609
+ }
3610
+ /**
3611
+ * {@link Settings} after locale resolution. Identical to the raw settings
3612
+ * except `skillCategories` labels are collapsed to single resolved strings
3613
+ * ({@link LocalizedSkillCategory}); every other settings field is passed
3614
+ * through unchanged.
3615
+ */
3616
+ type LocalizedSettings = Omit<Settings, 'skillCategories'> & {
3617
+ skillCategories?: LocalizedSkillCategory[];
3618
+ };
3256
3619
  /**
3257
3620
  * A takuhon document with every localized map flattened to a single string,
3258
3621
  * plus a `resolvedLocale` field recording which tag was actually used as the
3259
3622
  * head of the fallback chain. `resolveLocale()` returns this shape.
3260
3623
  *
3261
- * `Skill`, `Contact`, `Settings`, and `Meta` carry no localized fields and
3262
- * pass through unchanged.
3624
+ * `Skill`, `Contact`, and `Meta` carry no localized fields and pass through
3625
+ * unchanged; `Settings` passes through too, except its `skillCategories`
3626
+ * labels are resolved to the single locale string (see {@link LocalizedSettings}).
3263
3627
  */
3264
3628
  interface LocalizedTakuhon {
3265
3629
  schemaVersion: string;
@@ -3280,7 +3644,7 @@ interface LocalizedTakuhon {
3280
3644
  testScores: LocalizedTestScore[];
3281
3645
  recommendations: LocalizedRecommendation[];
3282
3646
  contact: Contact;
3283
- settings: Settings;
3647
+ settings: LocalizedSettings;
3284
3648
  meta: Meta;
3285
3649
  /**
3286
3650
  * The locale tag that was matched first by the fallback chain and used as
@@ -3326,7 +3690,7 @@ interface LocalizedTakuhon {
3326
3690
  * versions whose JSON Schema this package literally bundles, not the full
3327
3691
  * support window seen by end users.
3328
3692
  */
3329
- declare const SUPPORTED_SCHEMA_VERSIONS: readonly ["0.1.0", "0.2.0", "0.3.0", "0.4.0", "0.5.0", "0.6.0", "0.7.0", "1.0.0"];
3693
+ declare const SUPPORTED_SCHEMA_VERSIONS: readonly ["0.1.0", "0.2.0", "0.3.0", "0.4.0", "0.5.0", "0.6.0", "0.7.0", "1.0.0", "1.1.0", "1.2.0", "1.3.0"];
3330
3694
  /**
3331
3695
  * A single validation failure.
3332
3696
  *
@@ -4456,6 +4820,6 @@ declare function stripImageMetadata(bytes: Uint8Array, mime: AcceptedImageMime):
4456
4820
  * A takuhon profile document's `schemaVersion` field must be migrate-compatible
4457
4821
  * with this version. See operational-lifecycle docs for the migration policy.
4458
4822
  */
4459
- declare const SCHEMA_VERSION = "1.0.0";
4823
+ declare const SCHEMA_VERSION = "1.3.0";
4460
4824
 
4461
- export { ACCEPTED_IMAGE_MIME_TYPES, type AcceptedImageMime, type ActivitySettings, type ActivitySnapshot, type ActivityStorage, type Address, type AssetOptions, type AssetRecord, type Avatar, type Career, type Certification, type CodingTime, ConflictError, type Contact, type ContentLicense, type ContentLicenseAttribution, type ContributionCalendar, type ContributionDay, type Course, type CvDocument, type CvHeader, type CvSection, type CvSectionKind, DARK_PALETTE, type Education, type ExportOptions, type ExportedTakuhon, type GravatarOptions, type Honor, IMAGE_EXTENSIONS, type ImageInfo, ImportError, type Iso3166Alpha2, type IsoDateTime, LIGHT_PALETTE, type Language, type LanguageBreakdown, 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, MAX_IMAGE_BYTES, MAX_IMAGE_DIMENSION, MAX_IMAGE_FRAMES, MCP_PROFILE_SECTIONS, MCP_RESOURCES, MCP_TOOLS, type McpInputSchema, type McpProfileSection, McpRequestError, type McpResourceDefinition, type McpResourceResult, type McpToolDefinition, type McpToolResult, type Membership, type Meta, type MetaPrivacy, type Migration, MigrationError, type NormalizedTakuhon, NotFoundError, type Palette, type Patent, type PatentStatus, type Profile, type Project, type PublicVisibility, type Publication, RANK_FULL_CODING_HOURS, RANK_FULL_CONTRIBUTIONS, RANK_TIER_THRESHOLDS, type RankInput, type RankTier, type RankTierLabel, type Recommendation, type RecommendationAuthor, type RenderActivitySvgOptions, 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, computeLanguagePercentages, deriveCv, deriveRankTier, detectImageMime, executeMcpTool, exportTakuhon, formatCodingTime, formatDate, generateJsonLd, generatePersonJsonLd, generateProfilePageJsonLd, getPresentLabel, gravatarUrl, importTakuhon, isActivitySnapshot, migrateTakuhon, migrations, normalize, readImageInfo, readMcpResource, renderActivitySvg, resolveLocale, schema, stripImageMetadata, validate };
4825
+ export { ACCEPTED_IMAGE_MIME_TYPES, type AcceptedImageMime, type ActivitySettings, type ActivitySnapshot, type ActivityStorage, type Address, type AppearanceColors, type AppearanceSettings, type AssetOptions, type AssetRecord, type Avatar, type Career, type Certification, type CodingTime, ConflictError, type Contact, type ContentLicense, type ContentLicenseAttribution, type ContributionCalendar, type ContributionDay, type Course, type CvDocument, type CvHeader, type CvSection, type CvSectionKind, DARK_PALETTE, type Education, type ExportOptions, type ExportedTakuhon, type GravatarOptions, type Honor, IMAGE_EXTENSIONS, type ImageInfo, ImportError, type Iso3166Alpha2, type IsoDateTime, LIGHT_PALETTE, type Language, type LanguageBreakdown, 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, MAX_IMAGE_BYTES, MAX_IMAGE_DIMENSION, MAX_IMAGE_FRAMES, MCP_PROFILE_SECTIONS, MCP_RESOURCES, MCP_TOOLS, type McpInputSchema, type McpProfileSection, McpRequestError, type McpResourceDefinition, type McpResourceResult, type McpToolDefinition, type McpToolResult, type Membership, type Meta, type MetaPrivacy, type Migration, MigrationError, type NormalizedTakuhon, NotFoundError, type Palette, type Patent, type PatentStatus, type Profile, type Project, type PublicVisibility, type Publication, RANK_FULL_CODING_HOURS, RANK_FULL_CONTRIBUTIONS, RANK_TIER_THRESHOLDS, type RankInput, type RankTier, type RankTierLabel, type Recommendation, type RecommendationAuthor, type RenderActivitySvgOptions, 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, computeLanguagePercentages, deriveCv, deriveRankTier, detectImageMime, executeMcpTool, exportTakuhon, formatCodingTime, formatDate, generateJsonLd, generatePersonJsonLd, generateProfilePageJsonLd, getPresentLabel, gravatarUrl, importTakuhon, isActivitySnapshot, migrateTakuhon, migrations, normalize, readImageInfo, readMcpResource, renderActivitySvg, resolveLocale, schema, stripImageMetadata, validate };