@singi-labs/sifa-sdk 0.19.44 → 0.19.45
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/atproto/index.js +9 -3
- package/dist/atproto/index.js.map +1 -1
- package/dist/badge/index.js +5 -141
- package/dist/badge/index.js.map +1 -1
- package/dist/cards/adult-content.js +14 -0
- package/dist/cards/adult-content.js.map +1 -0
- package/dist/cards/app-url-patterns.js +369 -0
- package/dist/cards/app-url-patterns.js.map +1 -0
- package/dist/cards/index.js +24 -0
- package/dist/cards/index.js.map +1 -0
- package/dist/cards/resolve-card-url.js +198 -0
- package/dist/cards/resolve-card-url.js.map +1 -0
- package/dist/cards/visibility.js +45 -0
- package/dist/cards/visibility.js.map +1 -0
- package/dist/flags/index.js +4 -3
- package/dist/flags/index.js.map +1 -1
- package/dist/format/collapse-contributors.js +19 -0
- package/dist/format/collapse-contributors.js.map +1 -0
- package/dist/format/company-name.js +61 -0
- package/dist/format/company-name.js.map +1 -0
- package/dist/format/compare-text.js +9 -0
- package/dist/format/compare-text.js.map +1 -0
- package/dist/format/doi.js +8 -0
- package/dist/format/doi.js.map +1 -0
- package/dist/format/embed.js +131 -0
- package/dist/format/embed.js.map +1 -0
- package/dist/format/endorsement-context.js +35 -0
- package/dist/format/endorsement-context.js.map +1 -0
- package/dist/format/format-display-url.js +42 -0
- package/dist/format/format-display-url.js.map +1 -0
- package/dist/format/format-duration.js +13 -0
- package/dist/format/format-duration.js.map +1 -0
- package/dist/format/format-time.js +30 -0
- package/dist/format/format-time.js.map +1 -0
- package/dist/format/handle-utils.js +19 -0
- package/dist/format/handle-utils.js.map +1 -0
- package/dist/format/index.js +100 -0
- package/dist/format/index.js.map +1 -0
- package/dist/format/location-segments.js +29 -0
- package/dist/format/location-segments.js.map +1 -0
- package/dist/format/location-utils.js +42 -0
- package/dist/format/location-utils.js.map +1 -0
- package/dist/format/meta-description.js +35 -0
- package/dist/format/meta-description.js.map +1 -0
- package/dist/format/normalize-company-key.js +12 -0
- package/dist/format/normalize-company-key.js.map +1 -0
- package/dist/format/normalize-legal-form.js +71 -0
- package/dist/format/normalize-legal-form.js.map +1 -0
- package/dist/format/pds-utils.js +73 -0
- package/dist/format/pds-utils.js.map +1 -0
- package/dist/format/sort-by-date.js +39 -0
- package/dist/format/sort-by-date.js.map +1 -0
- package/dist/format/summarize-deliveries.js +37 -0
- package/dist/format/summarize-deliveries.js.map +1 -0
- package/dist/format/talk-slug.js +21 -0
- package/dist/format/talk-slug.js.map +1 -0
- package/dist/format/text-sanitize.js +29 -0
- package/dist/format/text-sanitize.js.map +1 -0
- package/dist/format/text-truncate.js +14 -0
- package/dist/format/text-truncate.js.map +1 -0
- package/dist/format/time-utils.js +19 -0
- package/dist/format/time-utils.js.map +1 -0
- package/dist/format/timeline.js +29 -0
- package/dist/format/timeline.js.map +1 -0
- package/dist/format/wcag-contrast.js +34 -0
- package/dist/format/wcag-contrast.js.map +1 -0
- package/dist/import/index.js +22 -0
- package/dist/import/index.js.map +1 -0
- package/dist/import/presentation-csv.js +116 -0
- package/dist/import/presentation-csv.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +675 -7086
- package/dist/index.js.map +1 -1
- package/dist/jev/index.js +18 -5
- package/dist/jev/index.js.map +1 -1
- package/dist/jsonld/index.js +30 -987
- package/dist/jsonld/index.js.map +1 -1
- package/dist/jsonld/profile.js +222 -0
- package/dist/jsonld/profile.js.map +1 -0
- package/dist/jsonld/terms.js +496 -0
- package/dist/jsonld/terms.js.map +1 -0
- package/dist/jsonld/url.js +17 -0
- package/dist/jsonld/url.js.map +1 -0
- package/dist/jsonld/works-graph.js +41 -0
- package/dist/jsonld/works-graph.js.map +1 -0
- package/dist/jsonld/works.js +178 -0
- package/dist/jsonld/works.js.map +1 -0
- package/dist/logic/actor-identity.js +8 -0
- package/dist/logic/actor-identity.js.map +1 -0
- package/dist/logic/agent-ref.js +24 -0
- package/dist/logic/agent-ref.js.map +1 -0
- package/dist/logic/company-page-indexable.js +23 -0
- package/dist/logic/company-page-indexable.js.map +1 -0
- package/dist/logic/date-lookahead.js +31 -0
- package/dist/logic/date-lookahead.js.map +1 -0
- package/dist/logic/domain-detect.js +43 -0
- package/dist/logic/domain-detect.js.map +1 -0
- package/dist/logic/entity-disambiguation.js +24 -0
- package/dist/logic/entity-disambiguation.js.map +1 -0
- package/dist/logic/entity-ref-anchor.js +33 -0
- package/dist/logic/entity-ref-anchor.js.map +1 -0
- package/dist/logic/index.js +91 -0
- package/dist/logic/index.js.map +1 -0
- package/dist/logic/org-floor.js +66 -0
- package/dist/logic/org-floor.js.map +1 -0
- package/dist/logic/primary-item.js +9 -0
- package/dist/logic/primary-item.js.map +1 -0
- package/dist/logic/primary-position.js +16 -0
- package/dist/logic/primary-position.js.map +1 -0
- package/dist/logic/profile-completeness.js +21 -0
- package/dist/logic/profile-completeness.js.map +1 -0
- package/dist/logic/profile-dimensions.js +50 -0
- package/dist/logic/profile-dimensions.js.map +1 -0
- package/dist/logic/profile-summary.js +23 -0
- package/dist/logic/profile-summary.js.map +1 -0
- package/dist/logic/pseudo-employer.js +34 -0
- package/dist/logic/pseudo-employer.js.map +1 -0
- package/dist/logic/recent-activity.js +10 -0
- package/dist/logic/recent-activity.js.map +1 -0
- package/dist/logic/self-app.js +10 -0
- package/dist/logic/self-app.js.map +1 -0
- package/dist/{org-BCrvebcf.d.ts → org-CxTEjjrm.d.ts} +1 -1
- package/dist/{org-settings-C73Sin5E.d.ts → org-settings-BShvhyFp.d.ts} +1 -1
- package/dist/profile/headline-role-dedupe.js +12 -0
- package/dist/profile/headline-role-dedupe.js.map +1 -0
- package/dist/profile/highlights.js +200 -0
- package/dist/profile/highlights.js.map +1 -0
- package/dist/profile/index.js +66 -0
- package/dist/profile/index.js.map +1 -0
- package/dist/profile/involvement-grouping.js +31 -0
- package/dist/profile/involvement-grouping.js.map +1 -0
- package/dist/profile/language-sort.js +24 -0
- package/dist/profile/language-sort.js.map +1 -0
- package/dist/profile/publication-versions.js +98 -0
- package/dist/profile/publication-versions.js.map +1 -0
- package/dist/profile/range-sort.js +14 -0
- package/dist/profile/range-sort.js.map +1 -0
- package/dist/profile/section-model.js +122 -0
- package/dist/profile/section-model.js.map +1 -0
- package/dist/profile/section-sorts.js +33 -0
- package/dist/profile/section-sorts.js.map +1 -0
- package/dist/publishers/index.js +16 -0
- package/dist/publishers/index.js.map +1 -0
- package/dist/publishers/registry.js +87 -0
- package/dist/publishers/registry.js.map +1 -0
- package/dist/publishing/index.js +46 -184
- package/dist/publishing/index.js.map +1 -1
- package/dist/publishing/linkblog.js +42 -0
- package/dist/publishing/linkblog.js.map +1 -0
- package/dist/publishing/registry.js +32 -0
- package/dist/publishing/registry.js.map +1 -0
- package/dist/publishing/schemas.js +74 -0
- package/dist/publishing/schemas.js.map +1 -0
- package/dist/publishing/types.js +32 -0
- package/dist/publishing/types.js.map +1 -0
- package/dist/query/client.js +119 -0
- package/dist/query/client.js.map +1 -0
- package/dist/query/config.js +23 -0
- package/dist/query/config.js.map +1 -0
- package/dist/query/fetchers/accounts.js +29 -0
- package/dist/query/fetchers/accounts.js.map +1 -0
- package/dist/query/fetchers/activity-items-hide.js +31 -0
- package/dist/query/fetchers/activity-items-hide.js.map +1 -0
- package/dist/query/fetchers/activity.js +61 -0
- package/dist/query/fetchers/activity.js.map +1 -0
- package/dist/query/fetchers/actor.js +30 -0
- package/dist/query/fetchers/actor.js.map +1 -0
- package/dist/query/fetchers/admin-feature-allowlists.js +41 -0
- package/dist/query/fetchers/admin-feature-allowlists.js.map +1 -0
- package/dist/query/fetchers/admin-review-queues.js +30 -0
- package/dist/query/fetchers/admin-review-queues.js.map +1 -0
- package/dist/query/fetchers/apps.js +31 -0
- package/dist/query/fetchers/apps.js.map +1 -0
- package/dist/query/fetchers/bsky-preferences.js +55 -0
- package/dist/query/fetchers/bsky-preferences.js.map +1 -0
- package/dist/query/fetchers/confirmations.js +55 -0
- package/dist/query/fetchers/confirmations.js.map +1 -0
- package/dist/query/fetchers/destructive.js +34 -0
- package/dist/query/fetchers/destructive.js.map +1 -0
- package/dist/query/fetchers/discovery.js +67 -0
- package/dist/query/fetchers/discovery.js.map +1 -0
- package/dist/query/fetchers/education.js +23 -0
- package/dist/query/fetchers/education.js.map +1 -0
- package/dist/query/fetchers/endorsement-inbox.js +36 -0
- package/dist/query/fetchers/endorsement-inbox.js.map +1 -0
- package/dist/query/fetchers/endorsement.js +23 -0
- package/dist/query/fetchers/endorsement.js.map +1 -0
- package/dist/query/fetchers/endorsements.js +20 -0
- package/dist/query/fetchers/endorsements.js.map +1 -0
- package/dist/query/fetchers/entities.js +65 -0
- package/dist/query/fetchers/entities.js.map +1 -0
- package/dist/query/fetchers/external-accounts.js +74 -0
- package/dist/query/fetchers/external-accounts.js.map +1 -0
- package/dist/query/fetchers/follow-extras.js +38 -0
- package/dist/query/fetchers/follow-extras.js.map +1 -0
- package/dist/query/fetchers/follow.js +105 -0
- package/dist/query/fetchers/follow.js.map +1 -0
- package/dist/query/fetchers/get-profile-view.js +21 -0
- package/dist/query/fetchers/get-profile-view.js.map +1 -0
- package/dist/query/fetchers/github-prs.js +45 -0
- package/dist/query/fetchers/github-prs.js.map +1 -0
- package/dist/query/fetchers/inbox.js +29 -0
- package/dist/query/fetchers/inbox.js.map +1 -0
- package/dist/query/fetchers/index.d.ts +2 -2
- package/dist/query/fetchers/index.js +360 -2045
- package/dist/query/fetchers/index.js.map +1 -1
- package/dist/query/fetchers/investments.js +18 -0
- package/dist/query/fetchers/investments.js.map +1 -0
- package/dist/query/fetchers/keytrace-claims.js +23 -0
- package/dist/query/fetchers/keytrace-claims.js.map +1 -0
- package/dist/query/fetchers/marque-domains.js +23 -0
- package/dist/query/fetchers/marque-domains.js.map +1 -0
- package/dist/query/fetchers/network-map.js +36 -0
- package/dist/query/fetchers/network-map.js.map +1 -0
- package/dist/query/fetchers/org.js +48 -0
- package/dist/query/fetchers/org.js.map +1 -0
- package/dist/query/fetchers/positions.js +77 -0
- package/dist/query/fetchers/positions.js.map +1 -0
- package/dist/query/fetchers/profile-completeness.js +45 -0
- package/dist/query/fetchers/profile-completeness.js.map +1 -0
- package/dist/query/fetchers/profile-items-hide.js +36 -0
- package/dist/query/fetchers/profile-items-hide.js.map +1 -0
- package/dist/query/fetchers/profile-locations.js +23 -0
- package/dist/query/fetchers/profile-locations.js.map +1 -0
- package/dist/query/fetchers/profile-mutations.js +82 -0
- package/dist/query/fetchers/profile-mutations.js.map +1 -0
- package/dist/query/fetchers/profile-summary.js +14 -0
- package/dist/query/fetchers/profile-summary.js.map +1 -0
- package/dist/query/fetchers/profile.js +31 -0
- package/dist/query/fetchers/profile.js.map +1 -0
- package/dist/query/fetchers/publications.js +66 -0
- package/dist/query/fetchers/publications.js.map +1 -0
- package/dist/query/fetchers/quoted-posts.js +40 -0
- package/dist/query/fetchers/quoted-posts.js.map +1 -0
- package/dist/query/fetchers/reactions.js +85 -0
- package/dist/query/fetchers/reactions.js.map +1 -0
- package/dist/query/fetchers/received-endorsements.js +20 -0
- package/dist/query/fetchers/received-endorsements.js.map +1 -0
- package/dist/query/fetchers/reciprocity.js +23 -0
- package/dist/query/fetchers/reciprocity.js.map +1 -0
- package/dist/query/fetchers/records.js +27 -0
- package/dist/query/fetchers/records.js.map +1 -0
- package/dist/query/fetchers/repo-inventory.js +23 -0
- package/dist/query/fetchers/repo-inventory.js.map +1 -0
- package/dist/query/fetchers/roadmap.js +73 -0
- package/dist/query/fetchers/roadmap.js.map +1 -0
- package/dist/query/fetchers/rpg.js +36 -0
- package/dist/query/fetchers/rpg.js.map +1 -0
- package/dist/query/fetchers/search.js +78 -0
- package/dist/query/fetchers/search.js.map +1 -0
- package/dist/query/fetchers/section-primary.js +23 -0
- package/dist/query/fetchers/section-primary.js.map +1 -0
- package/dist/query/fetchers/skills.js +30 -0
- package/dist/query/fetchers/skills.js.map +1 -0
- package/dist/query/fetchers/speakers.js +42 -0
- package/dist/query/fetchers/speakers.js.map +1 -0
- package/dist/query/fetchers/stats.js +16 -0
- package/dist/query/fetchers/stats.js.map +1 -0
- package/dist/query/fetchers/stream.js +30 -0
- package/dist/query/fetchers/stream.js.map +1 -0
- package/dist/query/fetchers/unlinked-positions.js +30 -0
- package/dist/query/fetchers/unlinked-positions.js.map +1 -0
- package/dist/query/hooks/index.d.ts +3 -3
- package/dist/query/hooks/index.js +283 -3555
- package/dist/query/hooks/index.js.map +1 -1
- package/dist/query/hooks/use-accounts.js +19 -0
- package/dist/query/hooks/use-accounts.js.map +1 -0
- package/dist/query/hooks/use-activity-items-hide.js +52 -0
- package/dist/query/hooks/use-activity-items-hide.js.map +1 -0
- package/dist/query/hooks/use-activity.js +44 -0
- package/dist/query/hooks/use-activity.js.map +1 -0
- package/dist/query/hooks/use-admin-review-queues.js +21 -0
- package/dist/query/hooks/use-admin-review-queues.js.map +1 -0
- package/dist/query/hooks/use-apps.js +31 -0
- package/dist/query/hooks/use-apps.js.map +1 -0
- package/dist/query/hooks/use-bsky-content-prefs.js +45 -0
- package/dist/query/hooks/use-bsky-content-prefs.js.map +1 -0
- package/dist/query/hooks/use-confirmations.js +121 -0
- package/dist/query/hooks/use-confirmations.js.map +1 -0
- package/dist/query/hooks/use-create-position.js +28 -0
- package/dist/query/hooks/use-create-position.js.map +1 -0
- package/dist/query/hooks/use-destructive.js +63 -0
- package/dist/query/hooks/use-destructive.js.map +1 -0
- package/dist/query/hooks/use-discovery.js +53 -0
- package/dist/query/hooks/use-discovery.js.map +1 -0
- package/dist/query/hooks/use-education-mutations.js +67 -0
- package/dist/query/hooks/use-education-mutations.js.map +1 -0
- package/dist/query/hooks/use-endorsement-inbox.js +80 -0
- package/dist/query/hooks/use-endorsement-inbox.js.map +1 -0
- package/dist/query/hooks/use-endorsement-mutations.js +33 -0
- package/dist/query/hooks/use-endorsement-mutations.js.map +1 -0
- package/dist/query/hooks/use-endorsement.js +20 -0
- package/dist/query/hooks/use-endorsement.js.map +1 -0
- package/dist/query/hooks/use-entity-search.js +73 -0
- package/dist/query/hooks/use-entity-search.js.map +1 -0
- package/dist/query/hooks/use-external-accounts.js +143 -0
- package/dist/query/hooks/use-external-accounts.js.map +1 -0
- package/dist/query/hooks/use-feature-allowlist.js +104 -0
- package/dist/query/hooks/use-feature-allowlist.js.map +1 -0
- package/dist/query/hooks/use-follow-extras.js +38 -0
- package/dist/query/hooks/use-follow-extras.js.map +1 -0
- package/dist/query/hooks/use-follow.js +113 -0
- package/dist/query/hooks/use-follow.js.map +1 -0
- package/dist/query/hooks/use-get-profile-view.js +20 -0
- package/dist/query/hooks/use-get-profile-view.js.map +1 -0
- package/dist/query/hooks/use-github-prs.js +21 -0
- package/dist/query/hooks/use-github-prs.js.map +1 -0
- package/dist/query/hooks/use-inbox.js +19 -0
- package/dist/query/hooks/use-inbox.js.map +1 -0
- package/dist/query/hooks/use-investment-mutations.js +65 -0
- package/dist/query/hooks/use-investment-mutations.js.map +1 -0
- package/dist/query/hooks/use-keytrace-claims.js +50 -0
- package/dist/query/hooks/use-keytrace-claims.js.map +1 -0
- package/dist/query/hooks/use-location-mutations.js +71 -0
- package/dist/query/hooks/use-location-mutations.js.map +1 -0
- package/dist/query/hooks/use-marque-domains.js +50 -0
- package/dist/query/hooks/use-marque-domains.js.map +1 -0
- package/dist/query/hooks/use-org-claim.js +29 -0
- package/dist/query/hooks/use-org-claim.js.map +1 -0
- package/dist/query/hooks/use-org-domains.js +28 -0
- package/dist/query/hooks/use-org-domains.js.map +1 -0
- package/dist/query/hooks/use-org-notification-emails.js +28 -0
- package/dist/query/hooks/use-org-notification-emails.js.map +1 -0
- package/dist/query/hooks/use-org-profile-settings.js +29 -0
- package/dist/query/hooks/use-org-profile-settings.js.map +1 -0
- package/dist/query/hooks/use-org-profile.js +21 -0
- package/dist/query/hooks/use-org-profile.js.map +1 -0
- package/dist/query/hooks/use-position-mutations.js +128 -0
- package/dist/query/hooks/use-position-mutations.js.map +1 -0
- package/dist/query/hooks/use-profile-completeness.js +21 -0
- package/dist/query/hooks/use-profile-completeness.js.map +1 -0
- package/dist/query/hooks/use-profile-items-hide.js +53 -0
- package/dist/query/hooks/use-profile-items-hide.js.map +1 -0
- package/dist/query/hooks/use-profile-mutations.js +143 -0
- package/dist/query/hooks/use-profile-mutations.js.map +1 -0
- package/dist/query/hooks/use-profile.js +30 -0
- package/dist/query/hooks/use-profile.js.map +1 -0
- package/dist/query/hooks/use-publication-mutations.js +90 -0
- package/dist/query/hooks/use-publication-mutations.js.map +1 -0
- package/dist/query/hooks/use-reaction-mutations.js +48 -0
- package/dist/query/hooks/use-reaction-mutations.js.map +1 -0
- package/dist/query/hooks/use-reactions.js +32 -0
- package/dist/query/hooks/use-reactions.js.map +1 -0
- package/dist/query/hooks/use-received-endorsements.js +23 -0
- package/dist/query/hooks/use-received-endorsements.js.map +1 -0
- package/dist/query/hooks/use-reciprocity.js +19 -0
- package/dist/query/hooks/use-reciprocity.js.map +1 -0
- package/dist/query/hooks/use-record-mutations.js +67 -0
- package/dist/query/hooks/use-record-mutations.js.map +1 -0
- package/dist/query/hooks/use-repo-inventory.js +43 -0
- package/dist/query/hooks/use-repo-inventory.js.map +1 -0
- package/dist/query/hooks/use-roadmap-mutations.js +51 -0
- package/dist/query/hooks/use-roadmap-mutations.js.map +1 -0
- package/dist/query/hooks/use-roadmap.js +31 -0
- package/dist/query/hooks/use-roadmap.js.map +1 -0
- package/dist/query/hooks/use-search.js +63 -0
- package/dist/query/hooks/use-search.js.map +1 -0
- package/dist/query/hooks/use-section-primary-mutations.js +53 -0
- package/dist/query/hooks/use-section-primary-mutations.js.map +1 -0
- package/dist/query/hooks/use-skill-mutations.js +91 -0
- package/dist/query/hooks/use-skill-mutations.js.map +1 -0
- package/dist/query/hooks/use-stats.js +19 -0
- package/dist/query/hooks/use-stats.js.map +1 -0
- package/dist/query/hooks/use-stream.js +20 -0
- package/dist/query/hooks/use-stream.js.map +1 -0
- package/dist/query/hooks/use-unlinked-positions.js +45 -0
- package/dist/query/hooks/use-unlinked-positions.js.map +1 -0
- package/dist/query/index.d.ts +4 -4
- package/dist/query/index.js +685 -3744
- package/dist/query/index.js.map +1 -1
- package/dist/query/keys.js +138 -0
- package/dist/query/keys.js.map +1 -0
- package/dist/repo/groups.js +81 -0
- package/dist/repo/groups.js.map +1 -0
- package/dist/repo/index.js +9 -0
- package/dist/repo/index.js.map +1 -0
- package/dist/repo/labels.js +121 -0
- package/dist/repo/labels.js.map +1 -0
- package/dist/repo/types.js +1 -0
- package/dist/repo/types.js.map +1 -0
- package/dist/resume/index.js +5 -179
- package/dist/resume/index.js.map +1 -1
- package/dist/resume/json-resume.js +153 -0
- package/dist/resume/json-resume.js.map +1 -0
- package/dist/roadmap/index.js +101 -0
- package/dist/roadmap/index.js.map +1 -0
- package/dist/rpg/catalog.js +101 -0
- package/dist/rpg/catalog.js.map +1 -0
- package/dist/rpg/index.js +13 -116
- package/dist/rpg/index.js.map +1 -1
- package/dist/rpg/unlocks.js +21 -0
- package/dist/rpg/unlocks.js.map +1 -0
- package/dist/schemas/blob-ref.js +12 -0
- package/dist/schemas/blob-ref.js.map +1 -0
- package/dist/schemas/confirmation.js +23 -0
- package/dist/schemas/confirmation.js.map +1 -0
- package/dist/schemas/endorsement-confirmation.js +18 -0
- package/dist/schemas/endorsement-confirmation.js.map +1 -0
- package/dist/schemas/endorsement.js +19 -0
- package/dist/schemas/endorsement.js.map +1 -0
- package/dist/schemas/entity.js +74 -0
- package/dist/schemas/entity.js.map +1 -0
- package/dist/schemas/feed.js +73 -0
- package/dist/schemas/feed.js.map +1 -0
- package/dist/schemas/follow-profile.js +32 -0
- package/dist/schemas/follow-profile.js.map +1 -0
- package/dist/schemas/graph-follow.js +19 -0
- package/dist/schemas/graph-follow.js.map +1 -0
- package/dist/schemas/index.js +164 -629
- package/dist/schemas/index.js.map +1 -1
- package/dist/schemas/org-employment-attestation.js +28 -0
- package/dist/schemas/org-employment-attestation.js.map +1 -0
- package/dist/schemas/org-profile.js +64 -0
- package/dist/schemas/org-profile.js.map +1 -0
- package/dist/schemas/profile-certification.js +28 -0
- package/dist/schemas/profile-certification.js.map +1 -0
- package/dist/schemas/profile-course.js +32 -0
- package/dist/schemas/profile-course.js.map +1 -0
- package/dist/schemas/profile-education.js +33 -0
- package/dist/schemas/profile-education.js.map +1 -0
- package/dist/schemas/profile-external-account.js +15 -0
- package/dist/schemas/profile-external-account.js.map +1 -0
- package/dist/schemas/profile-honor.js +18 -0
- package/dist/schemas/profile-honor.js.map +1 -0
- package/dist/schemas/profile-investment.js +48 -0
- package/dist/schemas/profile-investment.js.map +1 -0
- package/dist/schemas/profile-involvement.js +47 -0
- package/dist/schemas/profile-involvement.js.map +1 -0
- package/dist/schemas/profile-language.js +12 -0
- package/dist/schemas/profile-language.js.map +1 -0
- package/dist/schemas/profile-position.js +42 -0
- package/dist/schemas/profile-position.js.map +1 -0
- package/dist/schemas/profile-presentation-delivery.js +38 -0
- package/dist/schemas/profile-presentation-delivery.js.map +1 -0
- package/dist/schemas/profile-presentation.js +36 -0
- package/dist/schemas/profile-presentation.js.map +1 -0
- package/dist/schemas/profile-project.js +48 -0
- package/dist/schemas/profile-project.js.map +1 -0
- package/dist/schemas/profile-publication.js +30 -0
- package/dist/schemas/profile-publication.js.map +1 -0
- package/dist/schemas/profile-self.js +22 -0
- package/dist/schemas/profile-self.js.map +1 -0
- package/dist/schemas/profile-skill.js +13 -0
- package/dist/schemas/profile-skill.js.map +1 -0
- package/dist/schemas/profile-volunteering.js +20 -0
- package/dist/schemas/profile-volunteering.js.map +1 -0
- package/dist/schemas/shared.js +56 -0
- package/dist/schemas/shared.js.map +1 -0
- package/dist/schemas/write/certification.js +16 -0
- package/dist/schemas/write/certification.js.map +1 -0
- package/dist/schemas/write/course.js +36 -0
- package/dist/schemas/write/course.js.map +1 -0
- package/dist/schemas/write/education.js +18 -0
- package/dist/schemas/write/education.js.map +1 -0
- package/dist/schemas/write/external-account.js +13 -0
- package/dist/schemas/write/external-account.js.map +1 -0
- package/dist/schemas/write/honor.js +14 -0
- package/dist/schemas/write/honor.js.map +1 -0
- package/dist/schemas/write/index.d.ts +1 -1
- package/dist/schemas/write/index.js +89 -593
- package/dist/schemas/write/index.js.map +1 -1
- package/dist/schemas/write/investment.js +32 -0
- package/dist/schemas/write/investment.js.map +1 -0
- package/dist/schemas/write/involvement.js +34 -0
- package/dist/schemas/write/involvement.js.map +1 -0
- package/dist/schemas/write/language.js +10 -0
- package/dist/schemas/write/language.js.map +1 -0
- package/dist/schemas/write/org-claim.js +56 -0
- package/dist/schemas/write/org-claim.js.map +1 -0
- package/dist/schemas/write/org-employment-attestation.js +19 -0
- package/dist/schemas/write/org-employment-attestation.js.map +1 -0
- package/dist/schemas/write/org-profile.js +54 -0
- package/dist/schemas/write/org-profile.js.map +1 -0
- package/dist/schemas/write/org-settings.js +81 -0
- package/dist/schemas/write/org-settings.js.map +1 -0
- package/dist/schemas/write/position.js +24 -0
- package/dist/schemas/write/position.js.map +1 -0
- package/dist/schemas/write/presentation-delivery.js +34 -0
- package/dist/schemas/write/presentation-delivery.js.map +1 -0
- package/dist/schemas/write/presentation.js +23 -0
- package/dist/schemas/write/presentation.js.map +1 -0
- package/dist/schemas/write/profile-location.js +21 -0
- package/dist/schemas/write/profile-location.js.map +1 -0
- package/dist/schemas/write/profile-self.js +27 -0
- package/dist/schemas/write/profile-self.js.map +1 -0
- package/dist/schemas/write/project.js +27 -0
- package/dist/schemas/write/project.js.map +1 -0
- package/dist/schemas/write/publication.js +41 -0
- package/dist/schemas/write/publication.js.map +1 -0
- package/dist/schemas/write/shared.js +96 -0
- package/dist/schemas/write/shared.js.map +1 -0
- package/dist/schemas/write/skill.js +18 -0
- package/dist/schemas/write/skill.js.map +1 -0
- package/dist/schemas/write/volunteering.js +16 -0
- package/dist/schemas/write/volunteering.js.map +1 -0
- package/dist/stream/activity-item.js +1 -0
- package/dist/stream/activity-item.js.map +1 -0
- package/dist/stream/index.js +49 -0
- package/dist/stream/index.js.map +1 -0
- package/dist/stream/stream-card-vm-schema.js +265 -0
- package/dist/stream/stream-card-vm-schema.js.map +1 -0
- package/dist/stream/stream-card-vm.js +1 -0
- package/dist/stream/stream-card-vm.js.map +1 -0
- package/dist/stream/to-stream-card-vm.js +793 -0
- package/dist/stream/to-stream-card-vm.js.map +1 -0
- package/dist/stream/two-tier.js +30 -0
- package/dist/stream/two-tier.js.map +1 -0
- package/dist/stream/verbs.js +120 -0
- package/dist/stream/verbs.js.map +1 -0
- package/dist/taxonomy/activity-tiers.js +956 -0
- package/dist/taxonomy/activity-tiers.js.map +1 -0
- package/dist/taxonomy/app-categories.js +42 -0
- package/dist/taxonomy/app-categories.js.map +1 -0
- package/dist/taxonomy/app-category-map.js +166 -0
- package/dist/taxonomy/app-category-map.js.map +1 -0
- package/dist/taxonomy/artifact-link-kind.js +29 -0
- package/dist/taxonomy/artifact-link-kind.js.map +1 -0
- package/dist/taxonomy/calendar-event.js +28 -0
- package/dist/taxonomy/calendar-event.js.map +1 -0
- package/dist/taxonomy/continents.js +215 -0
- package/dist/taxonomy/continents.js.map +1 -0
- package/dist/taxonomy/countries.js +203 -0
- package/dist/taxonomy/countries.js.map +1 -0
- package/dist/taxonomy/course-role.js +37 -0
- package/dist/taxonomy/course-role.js.map +1 -0
- package/dist/taxonomy/employment-type.js +82 -0
- package/dist/taxonomy/employment-type.js.map +1 -0
- package/dist/taxonomy/eqf-level.js +59 -0
- package/dist/taxonomy/eqf-level.js.map +1 -0
- package/dist/taxonomy/index.js +263 -0
- package/dist/taxonomy/index.js.map +1 -0
- package/dist/taxonomy/industry-taxonomy.js +281 -0
- package/dist/taxonomy/industry-taxonomy.js.map +1 -0
- package/dist/taxonomy/investment.js +54 -0
- package/dist/taxonomy/investment.js.map +1 -0
- package/dist/taxonomy/involvement-kind.js +30 -0
- package/dist/taxonomy/involvement-kind.js.map +1 -0
- package/dist/taxonomy/open-to.js +128 -0
- package/dist/taxonomy/open-to.js.map +1 -0
- package/dist/taxonomy/platforms.js +56 -0
- package/dist/taxonomy/platforms.js.map +1 -0
- package/dist/taxonomy/presentation-link-type.js +22 -0
- package/dist/taxonomy/presentation-link-type.js.map +1 -0
- package/dist/taxonomy/presentation-role.js +21 -0
- package/dist/taxonomy/presentation-role.js.map +1 -0
- package/dist/taxonomy/publication-type.js +54 -0
- package/dist/taxonomy/publication-type.js.map +1 -0
- package/dist/taxonomy/relational.js +25 -0
- package/dist/taxonomy/relational.js.map +1 -0
- package/dist/taxonomy/search-filter-defs.js +66 -0
- package/dist/taxonomy/search-filter-defs.js.map +1 -0
- package/dist/taxonomy/skill-categories.js +28 -0
- package/dist/taxonomy/skill-categories.js.map +1 -0
- package/dist/taxonomy/skill-display-groups.js +12 -0
- package/dist/taxonomy/skill-display-groups.js.map +1 -0
- package/dist/taxonomy/skill-grouping.js +90 -0
- package/dist/taxonomy/skill-grouping.js.map +1 -0
- package/dist/taxonomy/verification-providers.js +69 -0
- package/dist/taxonomy/verification-providers.js.map +1 -0
- package/dist/taxonomy/workplace-type.js +38 -0
- package/dist/taxonomy/workplace-type.js.map +1 -0
- package/dist/tokens/colors.js +11 -0
- package/dist/tokens/colors.js.map +1 -0
- package/dist/tokens/icons.js +15 -0
- package/dist/tokens/icons.js.map +1 -0
- package/dist/tokens/index.js +10 -39
- package/dist/tokens/index.js.map +1 -1
- package/dist/tokens/typography.js +23 -0
- package/dist/tokens/typography.js.map +1 -0
- package/dist/types/index.js +10 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/profile-view.js +1 -0
- package/dist/types/profile-view.js.map +1 -0
- package/dist/{use-org-notification-emails-0hjt-dEw.d.ts → use-org-notification-emails-CWWi1D8t.d.ts} +2 -2
- package/package.json +4 -3
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// src/profile/involvement-grouping.ts
|
|
2
|
+
import { sortByDateDesc, lexiconDateExtractor } from "../format/sort-by-date.js";
|
|
3
|
+
import { getInvolvementKindHeading } from "../taxonomy/involvement-kind.js";
|
|
4
|
+
var INVOLVEMENT_HEADING_ORDER = [
|
|
5
|
+
"Open Source",
|
|
6
|
+
"Community",
|
|
7
|
+
"Volunteering",
|
|
8
|
+
"Civic",
|
|
9
|
+
"Other"
|
|
10
|
+
];
|
|
11
|
+
function groupInvolvementByHeading(items) {
|
|
12
|
+
const byHeading = /* @__PURE__ */ new Map();
|
|
13
|
+
for (const item of items) {
|
|
14
|
+
const heading = getInvolvementKindHeading(item.kind);
|
|
15
|
+
const bucket = byHeading.get(heading) ?? [];
|
|
16
|
+
bucket.push(item);
|
|
17
|
+
byHeading.set(heading, bucket);
|
|
18
|
+
}
|
|
19
|
+
const groups = [];
|
|
20
|
+
for (const heading of INVOLVEMENT_HEADING_ORDER) {
|
|
21
|
+
const bucket = byHeading.get(heading);
|
|
22
|
+
if (!bucket?.length) continue;
|
|
23
|
+
groups.push({ heading, items: sortByDateDesc(bucket, lexiconDateExtractor) });
|
|
24
|
+
}
|
|
25
|
+
return groups;
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
INVOLVEMENT_HEADING_ORDER,
|
|
29
|
+
groupInvolvementByHeading
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=involvement-grouping.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/profile/involvement-grouping.ts"],"sourcesContent":["import { sortByDateDesc, lexiconDateExtractor } from '../format/sort-by-date.js';\nimport { getInvolvementKindHeading } from '../taxonomy/involvement-kind.js';\nimport type { ProfileInvolvement } from '../types/index.js';\n\n/**\n * Fixed display order of involvement headings. A group renders only when it has\n * records. Charity + mapped legacy volunteering fall under \"Volunteering\".\n */\nexport const INVOLVEMENT_HEADING_ORDER = [\n 'Open Source',\n 'Community',\n 'Volunteering',\n 'Civic',\n 'Other',\n] as const;\n\nexport interface InvolvementGroup {\n heading: string;\n items: ProfileInvolvement[];\n}\n\n/**\n * Group involvement records by their kind's display heading, in the fixed order\n * above. Within a group, ongoing entries (no `endedAt`) float to the top, then\n * by end date descending, then start date descending -- the same current-first\n * ordering positions and education use (`lexiconDateExtractor`), so a role that\n * ended recently no longer sorts above a long-running current one. Empty groups\n * are omitted. An unknown kind falls under \"Other\" (via the shared heading map).\n */\nexport function groupInvolvementByHeading(items: ProfileInvolvement[]): InvolvementGroup[] {\n const byHeading = new Map<string, ProfileInvolvement[]>();\n for (const item of items) {\n const heading = getInvolvementKindHeading(item.kind);\n const bucket = byHeading.get(heading) ?? [];\n bucket.push(item);\n byHeading.set(heading, bucket);\n }\n const groups: InvolvementGroup[] = [];\n for (const heading of INVOLVEMENT_HEADING_ORDER) {\n const bucket = byHeading.get(heading);\n if (!bucket?.length) continue;\n groups.push({ heading, items: sortByDateDesc(bucket, lexiconDateExtractor) });\n }\n return groups;\n}\n"],"mappings":";AAAA,SAAS,gBAAgB,4BAA4B;AACrD,SAAS,iCAAiC;AAOnC,IAAM,4BAA4B;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAeO,SAAS,0BAA0B,OAAiD;AACzF,QAAM,YAAY,oBAAI,IAAkC;AACxD,aAAW,QAAQ,OAAO;AACxB,UAAM,UAAU,0BAA0B,KAAK,IAAI;AACnD,UAAM,SAAS,UAAU,IAAI,OAAO,KAAK,CAAC;AAC1C,WAAO,KAAK,IAAI;AAChB,cAAU,IAAI,SAAS,MAAM;AAAA,EAC/B;AACA,QAAM,SAA6B,CAAC;AACpC,aAAW,WAAW,2BAA2B;AAC/C,UAAM,SAAS,UAAU,IAAI,OAAO;AACpC,QAAI,CAAC,QAAQ,OAAQ;AACrB,WAAO,KAAK,EAAE,SAAS,OAAO,eAAe,QAAQ,oBAAoB,EAAE,CAAC;AAAA,EAC9E;AACA,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// src/profile/language-sort.ts
|
|
2
|
+
import { compareText } from "../format/compare-text.js";
|
|
3
|
+
var PROFICIENCY_RANK = {
|
|
4
|
+
native: 5,
|
|
5
|
+
full_professional: 4,
|
|
6
|
+
professional_working: 3,
|
|
7
|
+
limited_working: 2,
|
|
8
|
+
elementary: 1
|
|
9
|
+
};
|
|
10
|
+
function rank(proficiency) {
|
|
11
|
+
if (!proficiency) return 0;
|
|
12
|
+
return PROFICIENCY_RANK[proficiency] ?? 0;
|
|
13
|
+
}
|
|
14
|
+
function sortLanguagesByProficiency(items) {
|
|
15
|
+
return [...items].sort((a, b) => {
|
|
16
|
+
const diff = rank(b.proficiency) - rank(a.proficiency);
|
|
17
|
+
if (diff !== 0) return diff;
|
|
18
|
+
return compareText(a.language ?? "", b.language ?? "");
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
sortLanguagesByProficiency
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=language-sort.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/profile/language-sort.ts"],"sourcesContent":["import { compareText } from '../format/compare-text.js';\n\nconst PROFICIENCY_RANK: Record<string, number> = {\n native: 5,\n full_professional: 4,\n professional_working: 3,\n limited_working: 2,\n elementary: 1,\n};\n\nfunction rank(proficiency: string | undefined): number {\n if (!proficiency) return 0;\n return PROFICIENCY_RANK[proficiency] ?? 0;\n}\n\n/** Sort languages by proficiency (native first), then alphabetically within a rank. */\nexport function sortLanguagesByProficiency<T extends { language?: string; proficiency?: string }>(\n items: T[],\n): T[] {\n return [...items].sort((a, b) => {\n const diff = rank(b.proficiency) - rank(a.proficiency);\n if (diff !== 0) return diff;\n return compareText(a.language ?? '', b.language ?? '');\n });\n}\n"],"mappings":";AAAA,SAAS,mBAAmB;AAE5B,IAAM,mBAA2C;AAAA,EAC/C,QAAQ;AAAA,EACR,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,iBAAiB;AAAA,EACjB,YAAY;AACd;AAEA,SAAS,KAAK,aAAyC;AACrD,MAAI,CAAC,YAAa,QAAO;AACzB,SAAO,iBAAiB,WAAW,KAAK;AAC1C;AAGO,SAAS,2BACd,OACK;AACL,SAAO,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM;AAC/B,UAAM,OAAO,KAAK,EAAE,WAAW,IAAI,KAAK,EAAE,WAAW;AACrD,QAAI,SAAS,EAAG,QAAO;AACvB,WAAO,YAAY,EAAE,YAAY,IAAI,EAAE,YAAY,EAAE;AAAA,EACvD,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// src/profile/publication-versions.ts
|
|
2
|
+
import { normalizeDoi } from "../format/doi.js";
|
|
3
|
+
var PREPRINT_OF = /* @__PURE__ */ new Set(["IsPreprintOf", "IsPublishedIn"]);
|
|
4
|
+
var DEFERS_TO = /* @__PURE__ */ new Set(["IsVersionOf", "IsPreviousVersionOf"]);
|
|
5
|
+
var doiKey = (doi) => `doi:${normalizeDoi(doi).toLowerCase()}`;
|
|
6
|
+
function targetKey(rel) {
|
|
7
|
+
const id = rel.identifier?.trim();
|
|
8
|
+
if (!id) return void 0;
|
|
9
|
+
const type = rel.identifierType ?? "DOI";
|
|
10
|
+
if (type === "AT-URI") return `uri:${id}`;
|
|
11
|
+
if (type === "URL") {
|
|
12
|
+
const bare = normalizeDoi(id);
|
|
13
|
+
return bare.startsWith("10.") ? doiKey(bare) : `url:${id}`;
|
|
14
|
+
}
|
|
15
|
+
return doiKey(id);
|
|
16
|
+
}
|
|
17
|
+
function groupPublicationVersions(pubs, options = {}) {
|
|
18
|
+
const keyToIndex = /* @__PURE__ */ new Map();
|
|
19
|
+
pubs.forEach((p, i) => {
|
|
20
|
+
if (p.doi) keyToIndex.set(doiKey(p.doi), i);
|
|
21
|
+
if (options.ownerDid && (!p.source || p.source === "sifa")) {
|
|
22
|
+
keyToIndex.set(`uri:at://${options.ownerDid}/id.sifa.profile.publication/${p.rkey}`, i);
|
|
23
|
+
}
|
|
24
|
+
if (p.publicationUri) keyToIndex.set(`uri:${p.publicationUri}`, i);
|
|
25
|
+
});
|
|
26
|
+
const parent = pubs.map((_, i) => i);
|
|
27
|
+
const find = (i) => {
|
|
28
|
+
while (parent[i] !== i) {
|
|
29
|
+
parent[i] = parent[parent[i]];
|
|
30
|
+
i = parent[i];
|
|
31
|
+
}
|
|
32
|
+
return i;
|
|
33
|
+
};
|
|
34
|
+
const union = (a, b) => {
|
|
35
|
+
const ra = find(a);
|
|
36
|
+
const rb = find(b);
|
|
37
|
+
if (ra !== rb) parent[rb] = ra;
|
|
38
|
+
};
|
|
39
|
+
const preprints = /* @__PURE__ */ new Set();
|
|
40
|
+
const deferring = /* @__PURE__ */ new Set();
|
|
41
|
+
const siblingsOf = /* @__PURE__ */ new Map();
|
|
42
|
+
pubs.forEach((p, i) => {
|
|
43
|
+
if (p.type === "preprint") preprints.add(i);
|
|
44
|
+
for (const rel of p.relatedIdentifiers ?? []) {
|
|
45
|
+
const key = targetKey(rel);
|
|
46
|
+
if (!key) continue;
|
|
47
|
+
const j = keyToIndex.get(key);
|
|
48
|
+
if (j === void 0) {
|
|
49
|
+
if (rel.relationType === "IsVersionOf") {
|
|
50
|
+
const first = siblingsOf.get(key);
|
|
51
|
+
if (first === void 0) siblingsOf.set(key, i);
|
|
52
|
+
else union(first, i);
|
|
53
|
+
}
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (j === i) continue;
|
|
57
|
+
union(i, j);
|
|
58
|
+
if (PREPRINT_OF.has(rel.relationType)) preprints.add(i);
|
|
59
|
+
if (DEFERS_TO.has(rel.relationType)) deferring.add(i);
|
|
60
|
+
if (rel.relationType === "HasPreprint") preprints.add(j);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
const members = /* @__PURE__ */ new Map();
|
|
64
|
+
pubs.forEach((_, i) => {
|
|
65
|
+
const root = find(i);
|
|
66
|
+
const list = members.get(root);
|
|
67
|
+
if (list) list.push(i);
|
|
68
|
+
else members.set(root, [i]);
|
|
69
|
+
});
|
|
70
|
+
const newestFirst = (a, b) => {
|
|
71
|
+
const da = pubs[a].date ?? "";
|
|
72
|
+
const db = pubs[b].date ?? "";
|
|
73
|
+
if (da !== db) return db.localeCompare(da);
|
|
74
|
+
const fa = deferring.has(a) ? 1 : 0;
|
|
75
|
+
const fb = deferring.has(b) ? 1 : 0;
|
|
76
|
+
if (fa !== fb) return fa - fb;
|
|
77
|
+
return a - b;
|
|
78
|
+
};
|
|
79
|
+
const groups = [];
|
|
80
|
+
for (const indexes of members.values()) {
|
|
81
|
+
const primary = indexes.find((i) => pubs[i].primary);
|
|
82
|
+
const published = indexes.filter((i) => !preprints.has(i));
|
|
83
|
+
const pool = published.length ? published : indexes;
|
|
84
|
+
const lead = primary ?? [...pool].sort(newestFirst)[0];
|
|
85
|
+
groups.push({
|
|
86
|
+
order: Math.min(...indexes),
|
|
87
|
+
group: {
|
|
88
|
+
lead: pubs[lead],
|
|
89
|
+
versions: indexes.filter((i) => i !== lead).sort(newestFirst).map((i) => ({ pub: pubs[i], kind: preprints.has(i) ? "preprint" : "version" }))
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return groups.sort((a, b) => a.order - b.order).map((g) => g.group);
|
|
94
|
+
}
|
|
95
|
+
export {
|
|
96
|
+
groupPublicationVersions
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=publication-versions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/profile/publication-versions.ts"],"sourcesContent":["import { normalizeDoi } from '../format/doi.js';\nimport type { RelatedIdentifier } from '../types/index.js';\n\n/** The fields `groupPublicationVersions` reads from a publication. */\nexport interface VersionablePublication {\n rkey: string;\n doi?: string | null;\n type?: string | null;\n date?: string | null;\n primary?: boolean;\n source?: 'sifa' | 'standard' | 'orcid';\n publicationUri?: string | null;\n relatedIdentifiers?: readonly RelatedIdentifier[];\n}\n\n/** A publication shown as one entry, with its other versions folded under it. */\nexport interface PublicationVersionGroup<T> {\n lead: T;\n /** Other versions of the same work. `preprint` marks a preprint of the lead. */\n versions: { pub: T; kind: 'preprint' | 'version' }[];\n}\n\nexport interface GroupPublicationVersionsOptions {\n /**\n * DID of the profile owner. Needed to resolve an AT-URI relation to one of\n * the owner's own Sifa publications, which the view identifies by rkey.\n */\n ownerDid?: string;\n}\n\n/** Relations that point from a preprint to the version it became. */\nconst PREPRINT_OF = new Set(['IsPreprintOf', 'IsPublishedIn']);\n/** Relations that point from a version to the one it defers to. */\nconst DEFERS_TO = new Set(['IsVersionOf', 'IsPreviousVersionOf']);\n\nconst doiKey = (doi: string) => `doi:${normalizeDoi(doi).toLowerCase()}`;\n\n/** Resolve a related identifier to a lookup key, or undefined when it is not usable. */\nfunction targetKey(rel: RelatedIdentifier): string | undefined {\n const id = rel.identifier?.trim();\n if (!id) return undefined;\n const type = rel.identifierType ?? 'DOI';\n if (type === 'AT-URI') return `uri:${id}`;\n if (type === 'URL') {\n const bare = normalizeDoi(id);\n return bare.startsWith('10.') ? doiKey(bare) : `url:${id}`;\n }\n return doiKey(id);\n}\n\n/**\n * Fold the versions of one work into a single entry: a preprint under its\n * published version, older releases under the newest (#590).\n *\n * Publications are joined when one names another on the profile through a\n * DataCite-style relation (declared on the record or sourced from a registry),\n * in either direction, or when two name the same `IsVersionOf` target that is\n * not on the profile itself. Identifiers match on the bare, case-insensitive\n * DOI or on the AT-URI of the owner's own record.\n *\n * The lead of a group is the primary publication when it is in the group,\n * otherwise the newest one that is not a preprint; on a date tie, a member\n * that says it IsVersionOf / IsPreviousVersionOf another ranks after it. A preprint is a member typed\n * `preprint`, one that says it IsPreprintOf / IsPublishedIn another, or one a\n * member says it HasPreprint. Groups keep the order of their first member in\n * the input, so a caller's sort still applies.\n */\nexport function groupPublicationVersions<T extends VersionablePublication>(\n pubs: readonly T[],\n options: GroupPublicationVersionsOptions = {},\n): PublicationVersionGroup<T>[] {\n const keyToIndex = new Map<string, number>();\n pubs.forEach((p, i) => {\n if (p.doi) keyToIndex.set(doiKey(p.doi), i);\n if (options.ownerDid && (!p.source || p.source === 'sifa')) {\n keyToIndex.set(`uri:at://${options.ownerDid}/id.sifa.profile.publication/${p.rkey}`, i);\n }\n if (p.publicationUri) keyToIndex.set(`uri:${p.publicationUri}`, i);\n });\n\n // Union-find over publication indexes.\n const parent = pubs.map((_, i) => i);\n const find = (i: number): number => {\n while (parent[i] !== i) {\n parent[i] = parent[parent[i]!]!;\n i = parent[i]!;\n }\n return i;\n };\n const union = (a: number, b: number) => {\n const ra = find(a);\n const rb = find(b);\n if (ra !== rb) parent[rb] = ra;\n };\n\n const preprints = new Set<number>();\n // Members that point at another member as the canonical version; they rank\n // after it when dates do not decide (an undated arXiv copy of an article).\n const deferring = new Set<number>();\n const siblingsOf = new Map<string, number>();\n pubs.forEach((p, i) => {\n if (p.type === 'preprint') preprints.add(i);\n for (const rel of p.relatedIdentifiers ?? []) {\n const key = targetKey(rel);\n if (!key) continue;\n const j = keyToIndex.get(key);\n if (j === undefined) {\n // Two versions of one concept that is not itself on the profile.\n if (rel.relationType === 'IsVersionOf') {\n const first = siblingsOf.get(key);\n if (first === undefined) siblingsOf.set(key, i);\n else union(first, i);\n }\n continue;\n }\n if (j === i) continue;\n union(i, j);\n if (PREPRINT_OF.has(rel.relationType)) preprints.add(i);\n if (DEFERS_TO.has(rel.relationType)) deferring.add(i);\n if (rel.relationType === 'HasPreprint') preprints.add(j);\n }\n });\n\n const members = new Map<number, number[]>();\n pubs.forEach((_, i) => {\n const root = find(i);\n const list = members.get(root);\n if (list) list.push(i);\n else members.set(root, [i]);\n });\n\n const newestFirst = (a: number, b: number) => {\n const da = pubs[a]!.date ?? '';\n const db = pubs[b]!.date ?? '';\n if (da !== db) return db.localeCompare(da);\n const fa = deferring.has(a) ? 1 : 0;\n const fb = deferring.has(b) ? 1 : 0;\n if (fa !== fb) return fa - fb;\n return a - b;\n };\n\n const groups: { order: number; group: PublicationVersionGroup<T> }[] = [];\n for (const indexes of members.values()) {\n const primary = indexes.find((i) => pubs[i]!.primary);\n const published = indexes.filter((i) => !preprints.has(i));\n const pool = published.length ? published : indexes;\n const lead = primary ?? [...pool].sort(newestFirst)[0]!;\n groups.push({\n order: Math.min(...indexes),\n group: {\n lead: pubs[lead]!,\n versions: indexes\n .filter((i) => i !== lead)\n .sort(newestFirst)\n .map((i) => ({ pub: pubs[i]!, kind: preprints.has(i) ? 'preprint' : 'version' })),\n },\n });\n }\n return groups.sort((a, b) => a.order - b.order).map((g) => g.group);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// src/profile/range-sort.ts
|
|
2
|
+
import { sortByDateDesc } from "../format/sort-by-date.js";
|
|
3
|
+
var hasValue = (date) => !!date;
|
|
4
|
+
function sortByActiveDateRange(items) {
|
|
5
|
+
return sortByDateDesc(items, (p) => ({
|
|
6
|
+
startDate: p.startDate,
|
|
7
|
+
endDate: p.endDate,
|
|
8
|
+
current: !hasValue(p.endDate) && hasValue(p.startDate)
|
|
9
|
+
}));
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
sortByActiveDateRange
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=range-sort.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/profile/range-sort.ts"],"sourcesContent":["import { sortByDateDesc } from '../format/sort-by-date.js';\n\nconst hasValue = (date?: string) => !!date;\n\n/**\n * Sort items by date range, floating ongoing entries (startDate present, endDate\n * absent) to the top. Items with no dates sink to the bottom.\n *\n * Used by sections whose lexicons have no explicit `current` flag -- ongoing is\n * implicit from a missing endDate. Without this wrapper, the shared\n * `dateRangeExtractor` reads `item.current` (always undefined for these items)\n * and sinks ongoing entries below completed ones.\n *\n * Sections using lexicon-aligned `startedAt`/`endedAt` fields (positions,\n * education) should use `lexiconDateExtractor` instead -- that extractor already\n * derives `current` correctly.\n */\nexport function sortByActiveDateRange<T extends { startDate?: string; endDate?: string }>(\n items: T[],\n): T[] {\n return sortByDateDesc(items, (p) => ({\n startDate: p.startDate,\n endDate: p.endDate,\n current: !hasValue(p.endDate) && hasValue(p.startDate),\n }));\n}\n"],"mappings":";AAAA,SAAS,sBAAsB;AAE/B,IAAM,WAAW,CAAC,SAAkB,CAAC,CAAC;AAe/B,SAAS,sBACd,OACK;AACL,SAAO,eAAe,OAAO,CAAC,OAAO;AAAA,IACnC,WAAW,EAAE;AAAA,IACb,SAAS,EAAE;AAAA,IACX,SAAS,CAAC,SAAS,EAAE,OAAO,KAAK,SAAS,EAAE,SAAS;AAAA,EACvD,EAAE;AACJ;","names":[]}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// src/profile/section-model.ts
|
|
2
|
+
var SECTION_GROUPS = [
|
|
3
|
+
{ id: "overview", labelKey: "groupOverview" },
|
|
4
|
+
{ id: "experience", labelKey: "groupExperience" },
|
|
5
|
+
{ id: "qualifications", labelKey: "groupQualifications" },
|
|
6
|
+
{ id: "more", labelKey: "groupMore" }
|
|
7
|
+
];
|
|
8
|
+
var ALL_SECTIONS = [
|
|
9
|
+
{ id: "about", labelKey: "about", ns: "profile", group: "overview" },
|
|
10
|
+
{ id: "career", labelKey: "career", ns: "sections", group: "experience" },
|
|
11
|
+
{ id: "projects", labelKey: "projects", ns: "sections", group: "experience" },
|
|
12
|
+
{
|
|
13
|
+
id: "presentations",
|
|
14
|
+
labelKey: "talksAndSessions",
|
|
15
|
+
ns: "sections",
|
|
16
|
+
group: "experience"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: "publications",
|
|
20
|
+
labelKey: "publications",
|
|
21
|
+
ns: "sections",
|
|
22
|
+
group: "experience"
|
|
23
|
+
},
|
|
24
|
+
{ id: "skills", labelKey: "skills", ns: "sections", group: "experience" },
|
|
25
|
+
{
|
|
26
|
+
id: "credentials",
|
|
27
|
+
labelKey: "credentials",
|
|
28
|
+
ns: "sections",
|
|
29
|
+
group: "qualifications"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: "education",
|
|
33
|
+
labelKey: "education",
|
|
34
|
+
ns: "sections",
|
|
35
|
+
group: "qualifications"
|
|
36
|
+
},
|
|
37
|
+
{ id: "courses", labelKey: "courses", ns: "sections", group: "qualifications" },
|
|
38
|
+
{ id: "awards", labelKey: "awards", ns: "sections", group: "more" },
|
|
39
|
+
{ id: "involvement", labelKey: "involvement", ns: "sections", group: "more" },
|
|
40
|
+
// Its own section rather than a group under involvement: that record is about
|
|
41
|
+
// work contributed, this one about capital deployed.
|
|
42
|
+
{ id: "investments", labelKey: "investments", ns: "sections", group: "more" },
|
|
43
|
+
{ id: "languages", labelKey: "languages", ns: "sections", group: "more" },
|
|
44
|
+
{
|
|
45
|
+
id: "other-profiles",
|
|
46
|
+
labelKey: "otherProfiles",
|
|
47
|
+
ns: "sections",
|
|
48
|
+
group: "more"
|
|
49
|
+
}
|
|
50
|
+
];
|
|
51
|
+
function isSectionPopulated(profile, id) {
|
|
52
|
+
const hasVisible = (items) => filterHidden(items).length > 0;
|
|
53
|
+
switch (id) {
|
|
54
|
+
case "about":
|
|
55
|
+
return Boolean(profile.about && profile.headline);
|
|
56
|
+
case "career":
|
|
57
|
+
return hasVisible(profile.positions);
|
|
58
|
+
case "education":
|
|
59
|
+
return hasVisible(profile.education);
|
|
60
|
+
case "courses":
|
|
61
|
+
return hasVisible(profile.courses);
|
|
62
|
+
case "skills":
|
|
63
|
+
return Boolean(profile.skills?.length);
|
|
64
|
+
case "projects":
|
|
65
|
+
return hasVisible(profile.projects);
|
|
66
|
+
case "credentials":
|
|
67
|
+
return hasVisible(profile.certifications);
|
|
68
|
+
case "publications":
|
|
69
|
+
return hasVisible(profile.publications);
|
|
70
|
+
case "presentations":
|
|
71
|
+
return hasVisible(profile.presentations) || hasVisible(profile.presentationDeliveries);
|
|
72
|
+
case "involvement":
|
|
73
|
+
return hasVisible(profile.involvement);
|
|
74
|
+
case "investments":
|
|
75
|
+
return hasVisible(profile.investments);
|
|
76
|
+
case "awards":
|
|
77
|
+
return hasVisible(profile.honors);
|
|
78
|
+
case "languages":
|
|
79
|
+
return hasVisible(profile.languages);
|
|
80
|
+
case "other-profiles":
|
|
81
|
+
return hasVisible(profile.externalAccounts);
|
|
82
|
+
default:
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function getVisibleSectionIds(profile, isOwnProfile) {
|
|
87
|
+
return ALL_SECTIONS.map((s) => s.id).filter(
|
|
88
|
+
(id) => isOwnProfile || isSectionPopulated(profile, id)
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
function filterHidden(items) {
|
|
92
|
+
return (items ?? []).filter((i) => !i.hidden);
|
|
93
|
+
}
|
|
94
|
+
function visibleItems(items, isOwnProfile) {
|
|
95
|
+
return isOwnProfile ? items ?? [] : filterHidden(items);
|
|
96
|
+
}
|
|
97
|
+
var SECTION_LABELS = {
|
|
98
|
+
about: "About",
|
|
99
|
+
career: "Career",
|
|
100
|
+
skills: "Skills",
|
|
101
|
+
projects: "Projects",
|
|
102
|
+
presentations: "Talks & sessions",
|
|
103
|
+
publications: "Publications",
|
|
104
|
+
credentials: "Credentials",
|
|
105
|
+
education: "Education",
|
|
106
|
+
courses: "Courses",
|
|
107
|
+
awards: "Awards",
|
|
108
|
+
involvement: "Involvement",
|
|
109
|
+
investments: "Investments",
|
|
110
|
+
languages: "Languages",
|
|
111
|
+
"other-profiles": "Links"
|
|
112
|
+
};
|
|
113
|
+
export {
|
|
114
|
+
ALL_SECTIONS,
|
|
115
|
+
SECTION_GROUPS,
|
|
116
|
+
SECTION_LABELS,
|
|
117
|
+
filterHidden,
|
|
118
|
+
getVisibleSectionIds,
|
|
119
|
+
isSectionPopulated,
|
|
120
|
+
visibleItems
|
|
121
|
+
};
|
|
122
|
+
//# sourceMappingURL=section-model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/profile/section-model.ts"],"sourcesContent":["/**\n * Shared, single-source-of-truth model for which profile sections render, in\n * what order, their nav grouping, and which items a given viewer may see.\n *\n * Every Sifa profile surface builds on this: the HTML profile page, the\n * Markdown / DOCX / print exports, and the standalone personal-site renderer.\n * Adding a section to {@link ALL_SECTIONS} makes it appear everywhere (the\n * exports drive presence + order from here, and {@link SECTION_LABELS} is an\n * exhaustive `Record<SectionId, string>`, so a new id is a compile error until\n * it has a label).\n *\n * The per-section sorts live in `./section-sorts.js`, built on the same SDK\n * date extractors the HTML section components use, so the surfaces cannot\n * diverge on ordering.\n */\n\nimport type { Profile } from '../types/index.js';\n\n/**\n * Side-nav groups, in display order. Each labels a contiguous run of sections\n * in {@link ALL_SECTIONS}. `labelKey` resolves against the consumer's `sections`\n * i18n namespace.\n */\nexport const SECTION_GROUPS = [\n { id: 'overview', labelKey: 'groupOverview' },\n { id: 'experience', labelKey: 'groupExperience' },\n { id: 'qualifications', labelKey: 'groupQualifications' },\n { id: 'more', labelKey: 'groupMore' },\n] as const;\n\nexport type SectionGroupId = (typeof SECTION_GROUPS)[number]['id'];\n\n/**\n * Profile body sections in render + nav order (evidence-first): identity and\n * activity lead, then living work (career, projects, talks, publications, then\n * skills), then the formal record (credentials, education, courses), then the\n * rest. `ns` selects the consumer's i18n namespace for `labelKey`; `group`\n * ties the section to a {@link SECTION_GROUPS} header.\n */\nexport const ALL_SECTIONS = [\n { id: 'about', labelKey: 'about', ns: 'profile' as const, group: 'overview' as const },\n { id: 'career', labelKey: 'career', ns: 'sections' as const, group: 'experience' as const },\n { id: 'projects', labelKey: 'projects', ns: 'sections' as const, group: 'experience' as const },\n {\n id: 'presentations',\n labelKey: 'talksAndSessions',\n ns: 'sections' as const,\n group: 'experience' as const,\n },\n {\n id: 'publications',\n labelKey: 'publications',\n ns: 'sections' as const,\n group: 'experience' as const,\n },\n { id: 'skills', labelKey: 'skills', ns: 'sections' as const, group: 'experience' as const },\n {\n id: 'credentials',\n labelKey: 'credentials',\n ns: 'sections' as const,\n group: 'qualifications' as const,\n },\n {\n id: 'education',\n labelKey: 'education',\n ns: 'sections' as const,\n group: 'qualifications' as const,\n },\n { id: 'courses', labelKey: 'courses', ns: 'sections' as const, group: 'qualifications' as const },\n { id: 'awards', labelKey: 'awards', ns: 'sections' as const, group: 'more' as const },\n { id: 'involvement', labelKey: 'involvement', ns: 'sections' as const, group: 'more' as const },\n // Its own section rather than a group under involvement: that record is about\n // work contributed, this one about capital deployed.\n { id: 'investments', labelKey: 'investments', ns: 'sections' as const, group: 'more' as const },\n { id: 'languages', labelKey: 'languages', ns: 'sections' as const, group: 'more' as const },\n {\n id: 'other-profiles',\n labelKey: 'otherProfiles',\n ns: 'sections' as const,\n group: 'more' as const,\n },\n] as const;\n\n/** Every profile section id, in canonical render order. */\nexport type SectionId = (typeof ALL_SECTIONS)[number]['id'];\n\n/**\n * Whether a section has content a visitor can see (used to hide empty nav\n * entries and sections for visitors). Items the owner hid do not count: a\n * section whose only entries are hidden renders nothing for a visitor, so it\n * must not get a nav entry either.\n */\nexport function isSectionPopulated(profile: Profile, id: string): boolean {\n const hasVisible = <T extends { hidden?: boolean }>(items: T[] | undefined): boolean =>\n filterHidden(items).length > 0;\n switch (id) {\n case 'about':\n // Text fields, not hideable items. Without a headline the summary shows\n // in the identity card instead, so the About section stays out of it.\n return Boolean(profile.about && profile.headline);\n case 'career':\n return hasVisible(profile.positions);\n case 'education':\n return hasVisible(profile.education);\n case 'courses':\n return hasVisible(profile.courses);\n case 'skills':\n // Skills have no owner-hide flag (`ProfileSkill` carries no `hidden`).\n return Boolean(profile.skills?.length);\n case 'projects':\n return hasVisible(profile.projects);\n case 'credentials':\n return hasVisible(profile.certifications);\n case 'publications':\n return hasVisible(profile.publications);\n case 'presentations':\n return hasVisible(profile.presentations) || hasVisible(profile.presentationDeliveries);\n case 'involvement':\n return hasVisible(profile.involvement);\n case 'investments':\n return hasVisible(profile.investments);\n case 'awards':\n return hasVisible(profile.honors);\n case 'languages':\n return hasVisible(profile.languages);\n case 'other-profiles':\n return hasVisible(profile.externalAccounts);\n default:\n return false;\n }\n}\n\n/**\n * The section ids a given viewer should see, in {@link ALL_SECTIONS} order.\n * Owners see every section; visitors only see populated ones.\n */\nexport function getVisibleSectionIds(profile: Profile, isOwnProfile: boolean): SectionId[] {\n return ALL_SECTIONS.map((s) => s.id).filter(\n (id) => isOwnProfile || isSectionPopulated(profile, id),\n );\n}\n\n/** Drop items the owner has hidden from visitors. */\nexport function filterHidden<T extends { hidden?: boolean }>(items: T[] | undefined): T[] {\n return (items ?? []).filter((i) => !i.hidden);\n}\n\n/**\n * Items visible to a given viewer: owners see their own hidden items, visitors\n * do not. Shared by every export format (markdown, docx, print) and the public\n * `.md` route so the hidden rule lives in one place.\n */\nexport function visibleItems<T extends { hidden?: boolean }>(\n items: T[] | undefined,\n isOwnProfile: boolean,\n): T[] {\n return isOwnProfile ? (items ?? []) : filterHidden(items);\n}\n\n/**\n * English heading text for each section, keyed by {@link SectionId} (e.g.\n * `other-profiles` renders as \"Links\"). Exhaustive `Record<SectionId, string>`:\n * adding a section to {@link ALL_SECTIONS} without a label here is a compile\n * error, so a section can never silently render without (or with a stale)\n * heading. Consumers with i18n resolve their own localized labels via\n * `labelKey`; this is the canonical English fallback used by the exports.\n */\nexport const SECTION_LABELS: Record<SectionId, string> = {\n about: 'About',\n career: 'Career',\n skills: 'Skills',\n projects: 'Projects',\n presentations: 'Talks & sessions',\n publications: 'Publications',\n credentials: 'Credentials',\n education: 'Education',\n courses: 'Courses',\n awards: 'Awards',\n involvement: 'Involvement',\n investments: 'Investments',\n languages: 'Languages',\n 'other-profiles': 'Links',\n};\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// src/profile/section-sorts.ts
|
|
2
|
+
import {
|
|
3
|
+
sortByDateDesc,
|
|
4
|
+
lexiconDateExtractor,
|
|
5
|
+
singleDateExtractor,
|
|
6
|
+
certDateExtractor
|
|
7
|
+
} from "../format/sort-by-date.js";
|
|
8
|
+
import { sortByActiveDateRange } from "./range-sort.js";
|
|
9
|
+
import { sortLanguagesByProficiency } from "./language-sort.js";
|
|
10
|
+
function hoistPrimary(positions) {
|
|
11
|
+
const idx = positions.findIndex((p) => p.primary && !p.endedAt);
|
|
12
|
+
if (idx <= 0) return positions;
|
|
13
|
+
const primary = positions[idx];
|
|
14
|
+
return [primary, ...positions.slice(0, idx), ...positions.slice(idx + 1)];
|
|
15
|
+
}
|
|
16
|
+
var sortPositions = (items) => hoistPrimary(sortByDateDesc(items, lexiconDateExtractor));
|
|
17
|
+
var sortEducation = (items) => sortByDateDesc(items, lexiconDateExtractor);
|
|
18
|
+
var sortProjects = (items) => sortByActiveDateRange(items);
|
|
19
|
+
var sortPublications = (items) => sortByDateDesc(items, singleDateExtractor);
|
|
20
|
+
var sortCertifications = (items) => sortByDateDesc(items, certDateExtractor);
|
|
21
|
+
var sortHonors = (items) => sortByDateDesc(items, singleDateExtractor);
|
|
22
|
+
var sortLanguages = (items) => sortLanguagesByProficiency(items);
|
|
23
|
+
export {
|
|
24
|
+
hoistPrimary,
|
|
25
|
+
sortCertifications,
|
|
26
|
+
sortEducation,
|
|
27
|
+
sortHonors,
|
|
28
|
+
sortLanguages,
|
|
29
|
+
sortPositions,
|
|
30
|
+
sortProjects,
|
|
31
|
+
sortPublications
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=section-sorts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/profile/section-sorts.ts"],"sourcesContent":["/**\n * Per-section item sorts, shared by every profile surface so ordering can't\n * diverge between the HTML page and the Markdown / DOCX / print exports and the\n * standalone personal-site renderer. Thin wrappers over the SDK date extractors\n * plus the range/language sorts in this directory.\n */\n\nimport type {\n ProfilePosition,\n ProfileEducation,\n ProfileProject,\n ProfilePublication,\n ProfileCertification,\n ProfileHonor,\n ProfileLanguage,\n} from '../types/index.js';\nimport {\n sortByDateDesc,\n lexiconDateExtractor,\n singleDateExtractor,\n certDateExtractor,\n} from '../format/sort-by-date.js';\nimport { sortByActiveDateRange } from './range-sort.js';\nimport { sortLanguagesByProficiency } from './language-sort.js';\n\n/**\n * Move a `primary && !endedAt` position to the top, matching the HTML career\n * section, so the current primary role always leads.\n */\nexport function hoistPrimary(positions: ProfilePosition[]): ProfilePosition[] {\n const idx = positions.findIndex((p) => p.primary && !p.endedAt);\n if (idx <= 0) return positions;\n const primary = positions[idx]!;\n return [primary, ...positions.slice(0, idx), ...positions.slice(idx + 1)];\n}\n\nexport const sortPositions = (items: ProfilePosition[]): ProfilePosition[] =>\n hoistPrimary(sortByDateDesc(items, lexiconDateExtractor));\n\nexport const sortEducation = (items: ProfileEducation[]): ProfileEducation[] =>\n sortByDateDesc(items, lexiconDateExtractor);\n\nexport const sortProjects = (items: ProfileProject[]): ProfileProject[] =>\n sortByActiveDateRange(items);\n\nexport const sortPublications = (items: ProfilePublication[]): ProfilePublication[] =>\n sortByDateDesc(items, singleDateExtractor);\n\nexport const sortCertifications = (items: ProfileCertification[]): ProfileCertification[] =>\n sortByDateDesc(items, certDateExtractor);\n\nexport const sortHonors = (items: ProfileHonor[]): ProfileHonor[] =>\n sortByDateDesc(items, singleDateExtractor);\n\nexport const sortLanguages = (items: ProfileLanguage[]): ProfileLanguage[] =>\n sortLanguagesByProficiency(items);\n"],"mappings":";AAgBA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,6BAA6B;AACtC,SAAS,kCAAkC;AAMpC,SAAS,aAAa,WAAiD;AAC5E,QAAM,MAAM,UAAU,UAAU,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,OAAO;AAC9D,MAAI,OAAO,EAAG,QAAO;AACrB,QAAM,UAAU,UAAU,GAAG;AAC7B,SAAO,CAAC,SAAS,GAAG,UAAU,MAAM,GAAG,GAAG,GAAG,GAAG,UAAU,MAAM,MAAM,CAAC,CAAC;AAC1E;AAEO,IAAM,gBAAgB,CAAC,UAC5B,aAAa,eAAe,OAAO,oBAAoB,CAAC;AAEnD,IAAM,gBAAgB,CAAC,UAC5B,eAAe,OAAO,oBAAoB;AAErC,IAAM,eAAe,CAAC,UAC3B,sBAAsB,KAAK;AAEtB,IAAM,mBAAmB,CAAC,UAC/B,eAAe,OAAO,mBAAmB;AAEpC,IAAM,qBAAqB,CAAC,UACjC,eAAe,OAAO,iBAAiB;AAElC,IAAM,aAAa,CAAC,UACzB,eAAe,OAAO,mBAAmB;AAEpC,IAAM,gBAAgB,CAAC,UAC5B,2BAA2B,KAAK;","names":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/publishers/index.ts
|
|
2
|
+
import {
|
|
3
|
+
PUBLISHERS,
|
|
4
|
+
STANDARD_PUBLISHER_ID,
|
|
5
|
+
getPublisherById,
|
|
6
|
+
getPublisherByHost,
|
|
7
|
+
getPublisherFromSiteUrl
|
|
8
|
+
} from "./registry.js";
|
|
9
|
+
export {
|
|
10
|
+
PUBLISHERS,
|
|
11
|
+
STANDARD_PUBLISHER_ID,
|
|
12
|
+
getPublisherByHost,
|
|
13
|
+
getPublisherById,
|
|
14
|
+
getPublisherFromSiteUrl
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/publishers/index.ts"],"sourcesContent":["export {\n PUBLISHERS,\n STANDARD_PUBLISHER_ID,\n getPublisherById,\n getPublisherByHost,\n getPublisherFromSiteUrl,\n type Publisher,\n} from './registry.js';\n"],"mappings":";AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;","names":[]}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// src/publishers/registry.ts
|
|
2
|
+
var STANDARD_PUBLISHER_ID = "standard";
|
|
3
|
+
var PUBLISHERS = Object.freeze([
|
|
4
|
+
{
|
|
5
|
+
id: "leaflet",
|
|
6
|
+
name: "Leaflet",
|
|
7
|
+
hostSuffixes: ["leaflet.pub"],
|
|
8
|
+
homeUrl: "https://leaflet.pub"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: "pckt",
|
|
12
|
+
name: "pckt",
|
|
13
|
+
hostSuffixes: ["pckt.blog"],
|
|
14
|
+
homeUrl: "https://pckt.blog"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: "offprint",
|
|
18
|
+
name: "Offprint",
|
|
19
|
+
hostSuffixes: ["offprint.app"],
|
|
20
|
+
homeUrl: "https://offprint.app"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: "whitewind",
|
|
24
|
+
name: "WhiteWind",
|
|
25
|
+
hostSuffixes: ["whtwnd.com"],
|
|
26
|
+
homeUrl: "https://whtwnd.com"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: "unthread",
|
|
30
|
+
name: "Unthread",
|
|
31
|
+
hostSuffixes: ["unthread.at"],
|
|
32
|
+
homeUrl: "https://unthread.at"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "blento",
|
|
36
|
+
name: "Blento",
|
|
37
|
+
hostSuffixes: ["blento.io"],
|
|
38
|
+
homeUrl: "https://blento.io"
|
|
39
|
+
}
|
|
40
|
+
]);
|
|
41
|
+
var PUBLISHERS_BY_ID = new Map(PUBLISHERS.map((p) => [p.id, p]));
|
|
42
|
+
function getPublisherById(id) {
|
|
43
|
+
return PUBLISHERS_BY_ID.get(id);
|
|
44
|
+
}
|
|
45
|
+
function getPublisherByHost(hostname) {
|
|
46
|
+
const host = hostname.toLowerCase();
|
|
47
|
+
for (const publisher of PUBLISHERS) {
|
|
48
|
+
for (const suffix of publisher.hostSuffixes) {
|
|
49
|
+
if (host === suffix || host.endsWith(`.${suffix}`)) {
|
|
50
|
+
return publisher;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return void 0;
|
|
55
|
+
}
|
|
56
|
+
function getPublisherFromSiteUrl(siteUrl) {
|
|
57
|
+
let hostname;
|
|
58
|
+
let homeUrl;
|
|
59
|
+
try {
|
|
60
|
+
const parsed = new URL(siteUrl);
|
|
61
|
+
hostname = parsed.hostname;
|
|
62
|
+
homeUrl = `${parsed.protocol}//${parsed.hostname}`;
|
|
63
|
+
} catch {
|
|
64
|
+
return {
|
|
65
|
+
id: STANDARD_PUBLISHER_ID,
|
|
66
|
+
name: siteUrl,
|
|
67
|
+
hostSuffixes: [],
|
|
68
|
+
homeUrl: siteUrl
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const matched = getPublisherByHost(hostname);
|
|
72
|
+
if (matched) return matched;
|
|
73
|
+
return {
|
|
74
|
+
id: STANDARD_PUBLISHER_ID,
|
|
75
|
+
name: hostname,
|
|
76
|
+
hostSuffixes: [],
|
|
77
|
+
homeUrl
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export {
|
|
81
|
+
PUBLISHERS,
|
|
82
|
+
STANDARD_PUBLISHER_ID,
|
|
83
|
+
getPublisherByHost,
|
|
84
|
+
getPublisherById,
|
|
85
|
+
getPublisherFromSiteUrl
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/publishers/registry.ts"],"sourcesContent":["/**\n * Publisher registry — single source of truth for apps that publish documents\n * through the shared `site.standard.*` namespace (Leaflet, Pckt, Offprint, …).\n *\n * Why this exists:\n * A document published via Leaflet, Pckt, Offprint, etc. lives canonically as a\n * `site.standard.document` record. The publisher is metadata, identifiable from\n * the publication's hostname. The activity-card, the publication merger in\n * sifa-api, and the external-URL health scanner all need the same hostname →\n * publisher mapping. Keeping it in one place stops the registry from drifting.\n *\n * What lives here:\n * - `id` — stable appId, also keys sifa-web's branding (logo, color)\n * - `name` — display name\n * - `hostSuffixes` — hostnames that identify a publication URL as this publisher\n * - `homeUrl` — last-resort URL when no per-document URL is available\n *\n * What does NOT live here:\n * - Logo components, color tokens, React chrome — those belong in sifa-web\n * keyed by `id`.\n * - Per-document URL construction — Standard documents are always\n * `${publication.url}${document.path}`. The publisher doesn't change that.\n */\n\nexport interface Publisher {\n /**\n * Stable identifier. Used as the `appId` across Sifa so that sifa-web's\n * `getAppMeta(id)` lookup yields the right logo and color, and so that\n * activity-stat rows tag correctly.\n */\n id: string;\n\n /** Display name shown in pills and headers. */\n name: string;\n\n /**\n * Hostnames that identify a publication URL as belonging to this publisher.\n * Matches the publication URL's hostname when it equals the suffix\n * (e.g. `leaflet.pub`) OR ends with it as a dotted suffix\n * (e.g. `notesbyarielm.leaflet.pub`).\n *\n * Allow multiple entries to future-proof against rebrands or aliases.\n */\n hostSuffixes: readonly string[];\n\n /** Public homepage of the publisher, used as a profile-level fallback URL. */\n homeUrl: string;\n}\n\n/**\n * Neutral fallback used when no branded publisher matches.\n *\n * Synthetic publishers returned by `getPublisherFromSiteUrl` use this `id` but\n * carry the document's own hostname in `name`, so cards can still show e.g.\n * \"feeds.byarielm.fyi\" as the publisher label.\n */\nexport const STANDARD_PUBLISHER_ID = 'standard' as const;\n\nexport const PUBLISHERS: readonly Publisher[] = Object.freeze([\n {\n id: 'leaflet',\n name: 'Leaflet',\n hostSuffixes: ['leaflet.pub'],\n homeUrl: 'https://leaflet.pub',\n },\n {\n id: 'pckt',\n name: 'pckt',\n hostSuffixes: ['pckt.blog'],\n homeUrl: 'https://pckt.blog',\n },\n {\n id: 'offprint',\n name: 'Offprint',\n hostSuffixes: ['offprint.app'],\n homeUrl: 'https://offprint.app',\n },\n {\n id: 'whitewind',\n name: 'WhiteWind',\n hostSuffixes: ['whtwnd.com'],\n homeUrl: 'https://whtwnd.com',\n },\n {\n id: 'unthread',\n name: 'Unthread',\n hostSuffixes: ['unthread.at'],\n homeUrl: 'https://unthread.at',\n },\n {\n id: 'blento',\n name: 'Blento',\n hostSuffixes: ['blento.io'],\n homeUrl: 'https://blento.io',\n },\n]);\n\nconst PUBLISHERS_BY_ID: ReadonlyMap<string, Publisher> = new Map(PUBLISHERS.map((p) => [p.id, p]));\n\n/** Lookup a registered publisher by id. Returns `undefined` for unknown ids. */\nexport function getPublisherById(id: string): Publisher | undefined {\n return PUBLISHERS_BY_ID.get(id);\n}\n\n/**\n * Match a hostname against the registry. Returns the registered publisher when\n * the hostname equals or is a dotted-subdomain of any of its `hostSuffixes`.\n * Returns `undefined` when no match is found (caller decides on the fallback).\n */\nexport function getPublisherByHost(hostname: string): Publisher | undefined {\n const host = hostname.toLowerCase();\n for (const publisher of PUBLISHERS) {\n for (const suffix of publisher.hostSuffixes) {\n if (host === suffix || host.endsWith(`.${suffix}`)) {\n return publisher;\n }\n }\n }\n return undefined;\n}\n\n/**\n * Resolve the publisher for a publication's site URL.\n *\n * - On a branded host: returns the registered `Publisher` verbatim.\n * - On any other valid URL: returns a synthetic neutral publisher with\n * `id: 'standard'`, `name: <hostname>`, `hostSuffixes: []`, and the URL\n * as `homeUrl`. Cards can therefore always render a meaningful pill label.\n * - On an unparseable string: returns the same neutral shape with the raw\n * input as `name` and `homeUrl` (defensive — should never happen for data\n * coming from a valid `site.standard.publication`).\n */\nexport function getPublisherFromSiteUrl(siteUrl: string): Publisher {\n let hostname: string;\n let homeUrl: string;\n try {\n const parsed = new URL(siteUrl);\n hostname = parsed.hostname;\n homeUrl = `${parsed.protocol}//${parsed.hostname}`;\n } catch {\n return {\n id: STANDARD_PUBLISHER_ID,\n name: siteUrl,\n hostSuffixes: [],\n homeUrl: siteUrl,\n };\n }\n\n const matched = getPublisherByHost(hostname);\n if (matched) return matched;\n\n return {\n id: STANDARD_PUBLISHER_ID,\n name: hostname,\n hostSuffixes: [],\n homeUrl,\n };\n}\n"],"mappings":";AAwDO,IAAM,wBAAwB;AAE9B,IAAM,aAAmC,OAAO,OAAO;AAAA,EAC5D;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,cAAc,CAAC,aAAa;AAAA,IAC5B,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,cAAc,CAAC,WAAW;AAAA,IAC1B,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,cAAc,CAAC,cAAc;AAAA,IAC7B,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,cAAc,CAAC,YAAY;AAAA,IAC3B,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,cAAc,CAAC,aAAa;AAAA,IAC5B,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,cAAc,CAAC,WAAW;AAAA,IAC1B,SAAS;AAAA,EACX;AACF,CAAC;AAED,IAAM,mBAAmD,IAAI,IAAI,WAAW,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAG1F,SAAS,iBAAiB,IAAmC;AAClE,SAAO,iBAAiB,IAAI,EAAE;AAChC;AAOO,SAAS,mBAAmB,UAAyC;AAC1E,QAAM,OAAO,SAAS,YAAY;AAClC,aAAW,aAAa,YAAY;AAClC,eAAW,UAAU,UAAU,cAAc;AAC3C,UAAI,SAAS,UAAU,KAAK,SAAS,IAAI,MAAM,EAAE,GAAG;AAClD,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAaO,SAAS,wBAAwB,SAA4B;AAClE,MAAI;AACJ,MAAI;AACJ,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,OAAO;AAC9B,eAAW,OAAO;AAClB,cAAU,GAAG,OAAO,QAAQ,KAAK,OAAO,QAAQ;AAAA,EAClD,QAAQ;AACN,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,cAAc,CAAC;AAAA,MACf,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,UAAU,mBAAmB,QAAQ;AAC3C,MAAI,QAAS,QAAO;AAEpB,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,cAAc,CAAC;AAAA,IACf;AAAA,EACF;AACF;","names":[]}
|