@singi-labs/sifa-sdk 0.12.57 → 0.12.59

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.
Files changed (31) hide show
  1. package/dist/{index-Cd_heN1n.d.ts → index-B1WYOzm1.d.ts} +3 -2
  2. package/dist/{index-mXTN0GbN.d.cts → index-BcKfdI4X.d.cts} +3 -2
  3. package/dist/{types-Vf-kTiu1.d.cts → index-DMyroYoB.d.cts} +1 -509
  4. package/dist/{types-Vf-kTiu1.d.ts → index-DMyroYoB.d.ts} +1 -509
  5. package/dist/{index-DZGw-VDY.d.cts → index-Dqe0Nlck.d.cts} +4 -3
  6. package/dist/{index-GmKuSxp6.d.ts → index-czrerd84.d.ts} +4 -3
  7. package/dist/index.cjs +142 -117
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +30 -4
  10. package/dist/index.d.ts +30 -4
  11. package/dist/index.js +142 -118
  12. package/dist/index.js.map +1 -1
  13. package/dist/jsonld/index.cjs +891 -0
  14. package/dist/jsonld/index.cjs.map +1 -0
  15. package/dist/jsonld/index.d.cts +494 -0
  16. package/dist/jsonld/index.d.ts +494 -0
  17. package/dist/jsonld/index.js +878 -0
  18. package/dist/jsonld/index.js.map +1 -0
  19. package/dist/{org-fq2Xwg6Q.d.ts → org-66bQLHJd.d.ts} +2 -1
  20. package/dist/{org-CHVTcTcj.d.cts → org-GI1GVjZw.d.cts} +2 -1
  21. package/dist/{profile-summary-CdLI8k7M.d.cts → profile-summary-Bqj3TDVd.d.cts} +1 -1
  22. package/dist/{profile-summary-BS2GPBxw.d.ts → profile-summary-YZXjMymn.d.ts} +1 -1
  23. package/dist/query/fetchers/index.d.cts +5 -4
  24. package/dist/query/fetchers/index.d.ts +5 -4
  25. package/dist/query/hooks/index.d.cts +4 -3
  26. package/dist/query/hooks/index.d.ts +4 -3
  27. package/dist/query/index.d.cts +8 -7
  28. package/dist/query/index.d.ts +8 -7
  29. package/dist/types-BiBx2Utr.d.cts +511 -0
  30. package/dist/types-BkRDvKTp.d.ts +511 -0
  31. package/package.json +11 -1
@@ -0,0 +1,891 @@
1
+ 'use strict';
2
+
3
+ // src/jsonld/terms.ts
4
+ var VOCABULARIES = {
5
+ schema: "https://schema.org/",
6
+ bibo: "http://purl.org/ontology/bibo/",
7
+ dcterms: "http://purl.org/dc/terms/",
8
+ foaf: "http://xmlns.com/foaf/0.1/",
9
+ org: "http://www.w3.org/ns/org#",
10
+ prism: "http://prismstandard.org/namespaces/basic/2.1/",
11
+ event: "http://purl.org/NET/c4dm/event.owl#",
12
+ skos: "http://www.w3.org/2004/02/skos/core#"
13
+ };
14
+ var UNMAPPED = [
15
+ {
16
+ lexicon: "id.sifa.confirmation",
17
+ terms: [],
18
+ match: "noMatch",
19
+ note: "A record affirming another record is reification. schema:Review and schema:ClaimReview both imply an evaluation that a confirmation does not make."
20
+ },
21
+ {
22
+ lexicon: "id.sifa.endorsement",
23
+ terms: [],
24
+ match: "noMatch",
25
+ note: "Same reification problem as confirmation. Any mapping that lets a consumer aggregate endorsements into a score works against the descriptive-only trust model."
26
+ },
27
+ {
28
+ lexicon: "id.sifa.graph.connection",
29
+ terms: [],
30
+ match: "noMatch",
31
+ note: "foaf:knows carries no consent semantics. A Sifa connection is bilateral and confirmed; flattening it to foaf:knows would misrepresent an unconfirmed acquaintance claim as mutual."
32
+ },
33
+ {
34
+ lexicon: "id.sifa.graph.follow",
35
+ terms: [],
36
+ match: "noMatch",
37
+ note: "See id.sifa.graph.connection."
38
+ },
39
+ {
40
+ lexicon: "id.sifa.meeting",
41
+ terms: [],
42
+ match: "noMatch",
43
+ note: "Attestation semantics; same reification problem as confirmation."
44
+ }
45
+ ];
46
+ var PROFILE_SELF = [
47
+ { lexicon: "id.sifa.profile.self", terms: ["schema:Person", "foaf:Person"], match: "exactMatch" },
48
+ {
49
+ lexicon: "id.sifa.profile.self",
50
+ field: "displayName",
51
+ terms: ["schema:name", "foaf:name"],
52
+ match: "exactMatch"
53
+ },
54
+ {
55
+ lexicon: "id.sifa.profile.self",
56
+ field: "givenName",
57
+ terms: ["schema:givenName", "foaf:givenname"],
58
+ match: "exactMatch"
59
+ },
60
+ {
61
+ lexicon: "id.sifa.profile.self",
62
+ field: "familyName",
63
+ terms: ["schema:familyName", "foaf:family_name"],
64
+ match: "exactMatch"
65
+ },
66
+ {
67
+ lexicon: "id.sifa.profile.self",
68
+ field: "avatar",
69
+ terms: ["schema:image", "foaf:depiction"],
70
+ match: "exactMatch"
71
+ },
72
+ {
73
+ lexicon: "id.sifa.profile.self",
74
+ field: "headline",
75
+ terms: ["schema:jobTitle"],
76
+ match: "closeMatch"
77
+ },
78
+ {
79
+ lexicon: "id.sifa.profile.self",
80
+ field: "about",
81
+ terms: ["schema:description"],
82
+ match: "exactMatch"
83
+ },
84
+ {
85
+ lexicon: "id.sifa.profile.self",
86
+ field: "location",
87
+ terms: ["schema:homeLocation"],
88
+ match: "closeMatch"
89
+ },
90
+ {
91
+ lexicon: "id.sifa.profile.self",
92
+ field: "pronouns",
93
+ terms: [],
94
+ match: "noMatch",
95
+ note: "No stable external term. schema.org has no pronouns property."
96
+ },
97
+ {
98
+ lexicon: "id.sifa.profile.self",
99
+ field: "discoverable",
100
+ terms: [],
101
+ match: "noMatch",
102
+ note: "Sifa indexing control, not a fact about the person."
103
+ }
104
+ ];
105
+ var PROFILE_POSITION = [
106
+ {
107
+ lexicon: "id.sifa.profile.position",
108
+ terms: ["org:Membership", "schema:OrganizationRole"],
109
+ match: "closeMatch"
110
+ },
111
+ {
112
+ lexicon: "id.sifa.profile.position",
113
+ field: "company",
114
+ terms: ["org:organization", "schema:worksFor"],
115
+ match: "exactMatch"
116
+ },
117
+ {
118
+ lexicon: "id.sifa.profile.position",
119
+ field: "entityRef",
120
+ terms: ["schema:sameAs"],
121
+ match: "closeMatch"
122
+ },
123
+ {
124
+ lexicon: "id.sifa.profile.position",
125
+ field: "title",
126
+ terms: ["org:role", "schema:roleName"],
127
+ match: "exactMatch"
128
+ },
129
+ {
130
+ lexicon: "id.sifa.profile.position",
131
+ field: "description",
132
+ terms: ["dcterms:description"],
133
+ match: "exactMatch"
134
+ },
135
+ {
136
+ lexicon: "id.sifa.profile.position",
137
+ field: "employmentType",
138
+ terms: ["schema:employmentType"],
139
+ match: "closeMatch",
140
+ note: "schema:employmentType is free text. ESCO is the better value anchor."
141
+ },
142
+ {
143
+ lexicon: "id.sifa.profile.position",
144
+ field: "workplaceType",
145
+ terms: ["schema:jobLocationType"],
146
+ match: "narrowMatch",
147
+ note: "schema.org models only a remote flag; Sifa distinguishes onSite, remote, and hybrid."
148
+ },
149
+ {
150
+ lexicon: "id.sifa.profile.position",
151
+ field: "location",
152
+ terms: ["schema:jobLocation"],
153
+ match: "exactMatch"
154
+ },
155
+ {
156
+ lexicon: "id.sifa.profile.position",
157
+ field: "startedAt",
158
+ terms: ["schema:startDate"],
159
+ match: "exactMatch"
160
+ },
161
+ {
162
+ lexicon: "id.sifa.profile.position",
163
+ field: "endedAt",
164
+ terms: ["schema:endDate"],
165
+ match: "exactMatch"
166
+ },
167
+ {
168
+ lexicon: "id.sifa.profile.position",
169
+ field: "isPrimary",
170
+ terms: [],
171
+ match: "noMatch",
172
+ note: "Sifa display ordering concern."
173
+ }
174
+ ];
175
+ var PROFILE_EDUCATION = [
176
+ {
177
+ lexicon: "id.sifa.profile.education",
178
+ terms: ["schema:EducationalOccupationalCredential"],
179
+ match: "closeMatch",
180
+ note: "One record maps to two schema.org assertions: alumniOf for the institution and hasCredential for the degree."
181
+ },
182
+ {
183
+ lexicon: "id.sifa.profile.education",
184
+ field: "institution",
185
+ terms: ["schema:alumniOf"],
186
+ match: "exactMatch"
187
+ },
188
+ {
189
+ lexicon: "id.sifa.profile.education",
190
+ field: "degree",
191
+ terms: ["schema:hasCredential", "bibo:degree"],
192
+ match: "closeMatch"
193
+ },
194
+ {
195
+ lexicon: "id.sifa.profile.education",
196
+ field: "fieldOfStudy",
197
+ terms: ["schema:educationalCredentialAwarded"],
198
+ match: "closeMatch",
199
+ note: "ISCED-F is the value anchor."
200
+ },
201
+ {
202
+ lexicon: "id.sifa.profile.education",
203
+ field: "grade",
204
+ terms: [],
205
+ match: "noMatch",
206
+ note: "No comparable external term; grading scales are not portable."
207
+ }
208
+ ];
209
+ var PROFILE_PUBLICATION = [
210
+ {
211
+ lexicon: "id.sifa.profile.publication",
212
+ terms: ["bibo:Document", "schema:CreativeWork"],
213
+ match: "broadMatch",
214
+ note: "Refine to bibo:AcademicArticle, bibo:Book, bibo:Report or bibo:Thesis when a resource type is known. COAR is the value anchor."
215
+ },
216
+ {
217
+ lexicon: "id.sifa.profile.publication",
218
+ field: "title",
219
+ terms: ["dcterms:title", "schema:name"],
220
+ match: "exactMatch"
221
+ },
222
+ {
223
+ lexicon: "id.sifa.profile.publication",
224
+ field: "subtitle",
225
+ terms: ["schema:alternativeHeadline"],
226
+ match: "closeMatch"
227
+ },
228
+ {
229
+ lexicon: "id.sifa.profile.publication",
230
+ field: "publisher",
231
+ terms: ["dcterms:publisher", "schema:publisher"],
232
+ match: "exactMatch"
233
+ },
234
+ {
235
+ lexicon: "id.sifa.profile.publication",
236
+ field: "url",
237
+ terms: ["bibo:uri", "schema:url"],
238
+ match: "exactMatch"
239
+ },
240
+ {
241
+ lexicon: "id.sifa.profile.publication",
242
+ field: "description",
243
+ terms: ["bibo:abstract", "schema:abstract"],
244
+ match: "exactMatch"
245
+ },
246
+ {
247
+ lexicon: "id.sifa.profile.publication",
248
+ field: "authors",
249
+ terms: ["bibo:authorList", "schema:author"],
250
+ match: "exactMatch",
251
+ note: "bibo:authorList is an ordered rdf:List and preserves author order, which schema:author does not guarantee."
252
+ },
253
+ {
254
+ lexicon: "id.sifa.profile.publication",
255
+ field: "publishedAt",
256
+ terms: ["dcterms:issued", "schema:datePublished"],
257
+ match: "exactMatch"
258
+ },
259
+ {
260
+ lexicon: "id.sifa.profile.publication",
261
+ field: "doi",
262
+ terms: ["bibo:doi", "prism:doi"],
263
+ match: "exactMatch",
264
+ note: "Present on the AppView view type (ORCID-sourced), not yet on the id.sifa.profile.publication lexicon, so user-authored publications cannot carry one."
265
+ }
266
+ ];
267
+ var PROFILE_PRESENTATION = [
268
+ {
269
+ lexicon: "id.sifa.profile.presentation",
270
+ terms: ["bibo:Slideshow", "schema:PresentationDigitalDocument"],
271
+ match: "closeMatch",
272
+ note: 'Neither term carries the "reusable, deliverable more than once" semantics of the Sifa record.'
273
+ },
274
+ {
275
+ lexicon: "id.sifa.profile.presentation",
276
+ field: "title",
277
+ terms: ["dcterms:title", "schema:name"],
278
+ match: "exactMatch"
279
+ },
280
+ {
281
+ lexicon: "id.sifa.profile.presentation",
282
+ field: "description",
283
+ terms: ["bibo:abstract", "schema:abstract"],
284
+ match: "exactMatch"
285
+ },
286
+ {
287
+ lexicon: "id.sifa.profile.presentation",
288
+ field: "duration",
289
+ terms: ["schema:timeRequired"],
290
+ match: "narrowMatch",
291
+ note: "The lexicon models a range; schema:timeRequired is a single ISO 8601 duration."
292
+ },
293
+ {
294
+ lexicon: "id.sifa.profile.presentation",
295
+ field: "intendedAudiences",
296
+ terms: ["schema:audience"],
297
+ match: "closeMatch"
298
+ },
299
+ {
300
+ lexicon: "id.sifa.profile.presentation",
301
+ field: "writeupRef",
302
+ terms: ["dcterms:isReferencedBy", "schema:subjectOf"],
303
+ match: "closeMatch"
304
+ },
305
+ {
306
+ lexicon: "id.sifa.profile.presentation",
307
+ field: "coverImage",
308
+ terms: ["schema:image", "foaf:depiction"],
309
+ match: "exactMatch"
310
+ }
311
+ ];
312
+ var PROFILE_PRESENTATION_DELIVERY = [
313
+ {
314
+ lexicon: "id.sifa.profile.presentationDelivery",
315
+ terms: ["schema:Event", "event:Event"],
316
+ match: "closeMatch",
317
+ note: "BIBO models this relation as bibo:Slideshow bibo:presentedAt event:Event."
318
+ },
319
+ {
320
+ lexicon: "id.sifa.profile.presentationDelivery",
321
+ field: "presentationRef",
322
+ terms: ["bibo:presentedAt", "schema:workPerformed"],
323
+ match: "closeMatch"
324
+ },
325
+ {
326
+ lexicon: "id.sifa.profile.presentationDelivery",
327
+ field: "title",
328
+ terms: ["dcterms:title", "schema:name"],
329
+ match: "exactMatch"
330
+ },
331
+ {
332
+ lexicon: "id.sifa.profile.presentationDelivery",
333
+ field: "role",
334
+ terms: ["bibo:performer", "schema:performer"],
335
+ match: "closeMatch",
336
+ note: "No external vocabulary distinguishes presenter, panelist, keynote, workshop and host at this granularity."
337
+ },
338
+ {
339
+ lexicon: "id.sifa.profile.presentationDelivery",
340
+ field: "eventName",
341
+ terms: ["schema:superEvent", "bibo:Conference"],
342
+ match: "closeMatch"
343
+ },
344
+ {
345
+ lexicon: "id.sifa.profile.presentationDelivery",
346
+ field: "date",
347
+ terms: ["schema:startDate", "event:time"],
348
+ match: "exactMatch"
349
+ },
350
+ {
351
+ lexicon: "id.sifa.profile.presentationDelivery",
352
+ field: "address",
353
+ terms: ["schema:location", "event:place"],
354
+ match: "exactMatch"
355
+ },
356
+ {
357
+ lexicon: "id.sifa.profile.presentationDelivery",
358
+ field: "mode",
359
+ terms: ["schema:eventAttendanceMode"],
360
+ match: "exactMatch",
361
+ note: "The community.lexicon.calendar.event known values are already one-to-one with the schema.org enumeration."
362
+ },
363
+ {
364
+ lexicon: "id.sifa.profile.presentationDelivery",
365
+ field: "status",
366
+ terms: ["schema:eventStatus"],
367
+ match: "exactMatch",
368
+ note: "As with mode, already one-to-one with the schema.org enumeration."
369
+ },
370
+ {
371
+ lexicon: "id.sifa.profile.presentationDelivery",
372
+ field: "coSpeakers",
373
+ terms: ["schema:performer"],
374
+ match: "exactMatch"
375
+ }
376
+ ];
377
+ var PROFILE_OTHER = [
378
+ {
379
+ lexicon: "id.sifa.profile.certification",
380
+ terms: ["schema:EducationalOccupationalCredential"],
381
+ match: "exactMatch"
382
+ },
383
+ {
384
+ lexicon: "id.sifa.profile.certification",
385
+ field: "credentialUrl",
386
+ terms: ["schema:url"],
387
+ match: "exactMatch"
388
+ },
389
+ {
390
+ lexicon: "id.sifa.profile.certification",
391
+ field: "expiresAt",
392
+ terms: ["schema:validUntil"],
393
+ match: "exactMatch"
394
+ },
395
+ { lexicon: "id.sifa.profile.course", terms: ["schema:Course"], match: "exactMatch" },
396
+ {
397
+ lexicon: "id.sifa.profile.course",
398
+ field: "number",
399
+ terms: ["schema:courseCode"],
400
+ match: "exactMatch"
401
+ },
402
+ {
403
+ lexicon: "id.sifa.profile.honor",
404
+ terms: ["schema:award"],
405
+ match: "broadMatch",
406
+ note: "schema:award is a bare string, so issuer and date are lost. No better term exists in BIBO either."
407
+ },
408
+ {
409
+ lexicon: "id.sifa.profile.project",
410
+ terms: ["schema:Project", "foaf:Project"],
411
+ match: "exactMatch"
412
+ },
413
+ {
414
+ lexicon: "id.sifa.profile.skill",
415
+ terms: ["schema:knowsAbout", "schema:DefinedTerm"],
416
+ match: "closeMatch",
417
+ note: "ESCO is the value anchor."
418
+ },
419
+ {
420
+ lexicon: "id.sifa.profile.volunteering",
421
+ terms: ["org:Membership", "schema:OrganizationRole"],
422
+ match: "closeMatch"
423
+ },
424
+ {
425
+ lexicon: "id.sifa.profile.involvement",
426
+ terms: ["org:Membership"],
427
+ match: "broadMatch",
428
+ note: "The kind known values have no external equivalent."
429
+ },
430
+ {
431
+ lexicon: "id.sifa.profile.language",
432
+ terms: ["schema:knowsLanguage"],
433
+ match: "exactMatch"
434
+ },
435
+ {
436
+ lexicon: "id.sifa.profile.language",
437
+ field: "proficiency",
438
+ terms: [],
439
+ match: "noMatch",
440
+ note: "The known values are CEFR-shaped but not CEFR-named. Map only; renaming a published lexicon for a cosmetic gain is not worth the break."
441
+ },
442
+ {
443
+ lexicon: "id.sifa.profile.externalAccount",
444
+ terms: ["schema:sameAs", "foaf:account"],
445
+ match: "exactMatch"
446
+ },
447
+ {
448
+ lexicon: "id.sifa.org.profile",
449
+ terms: ["schema:Organization", "org:FormalOrganization"],
450
+ match: "exactMatch",
451
+ note: "ROR is the value anchor."
452
+ }
453
+ ];
454
+ var TERM_MAPPINGS = [
455
+ ...PROFILE_SELF,
456
+ ...PROFILE_POSITION,
457
+ ...PROFILE_EDUCATION,
458
+ ...PROFILE_PUBLICATION,
459
+ ...PROFILE_PRESENTATION,
460
+ ...PROFILE_PRESENTATION_DELIVERY,
461
+ ...PROFILE_OTHER,
462
+ ...UNMAPPED
463
+ ];
464
+ function expandCurie(curie) {
465
+ const separator = curie.indexOf(":");
466
+ if (separator <= 0) return null;
467
+ const prefix = curie.slice(0, separator);
468
+ const local = curie.slice(separator + 1);
469
+ if (!local) return null;
470
+ if (!Object.prototype.hasOwnProperty.call(VOCABULARIES, prefix)) return null;
471
+ return `${VOCABULARIES[prefix]}${local}`;
472
+ }
473
+ function mappingsForLexicon(nsid) {
474
+ return TERM_MAPPINGS.filter((m) => m.lexicon === nsid);
475
+ }
476
+ function isDeliberatelyUnmapped(nsid, field) {
477
+ return TERM_MAPPINGS.some(
478
+ (m) => m.lexicon === nsid && m.field === field && m.match === "noMatch"
479
+ );
480
+ }
481
+
482
+ // src/format/location-utils.ts
483
+ function formatLocation(loc) {
484
+ if (!loc) return "";
485
+ const locality = loc.locality ?? loc.city;
486
+ const parts = [locality, loc.region, loc.country].filter(Boolean);
487
+ if (loc.postalCode && !locality) {
488
+ return `${loc.postalCode}, ${loc.country}`;
489
+ }
490
+ return parts.join(", ");
491
+ }
492
+
493
+ // src/logic/primary-position.ts
494
+ function pickPrimaryPosition(positions) {
495
+ if (!positions || positions.length === 0) return void 0;
496
+ const active = positions.filter((p) => !p.endedAt);
497
+ if (active.length === 0) return void 0;
498
+ const flagged = active.find((p) => p.primary === true);
499
+ if (flagged) return flagged;
500
+ return [...active].sort((a, b) => (b.startedAt ?? "").localeCompare(a.startedAt ?? ""))[0];
501
+ }
502
+
503
+ // src/profile/section-model.ts
504
+ function filterHidden(items) {
505
+ return (items ?? []).filter((i) => !i.hidden);
506
+ }
507
+
508
+ // src/jsonld/url.ts
509
+ var DEFAULT_BASE_URL = "https://sifa.id";
510
+ function normaliseBaseUrl(baseUrl) {
511
+ const value = baseUrl ?? DEFAULT_BASE_URL;
512
+ let end = value.length;
513
+ while (end > 0 && value.charCodeAt(end - 1) === 47) end -= 1;
514
+ return value.slice(0, end);
515
+ }
516
+ function profileUrl(baseUrl, handle) {
517
+ return `${baseUrl}/p/${handle}`;
518
+ }
519
+
520
+ // src/jsonld/profile.ts
521
+ var MAX_KNOWS_ABOUT = 20;
522
+ var MEANINGFUL_TEXT_RE = /[\p{L}\p{N}]/u;
523
+ var identity = (input) => input;
524
+ function hasMeaningfulText(value) {
525
+ return typeof value === "string" && MEANINGFUL_TEXT_RE.test(value);
526
+ }
527
+ function visible(items) {
528
+ return filterHidden(items ? [...items] : void 0);
529
+ }
530
+ function rankKnowsAbout(skills, s) {
531
+ const ranked = visible(skills).filter((sk) => Boolean(sk.name)).sort((a, b) => (b.endorsementCount ?? 0) - (a.endorsementCount ?? 0)).slice(0, MAX_KNOWS_ABOUT).map((sk) => s(sk.name));
532
+ return ranked.length > 0 ? ranked : void 0;
533
+ }
534
+ function buildSameAs(profile) {
535
+ const sameAs = [];
536
+ const hasBluesky = profile.activeApps?.some((a) => a.id === "bluesky") ?? false;
537
+ if (hasBluesky) sameAs.push(`https://bsky.app/profile/${profile.handle}`);
538
+ if (profile.website) {
539
+ const url = profile.website.startsWith("http") ? profile.website : `https://${profile.website}`;
540
+ if (!sameAs.includes(url)) sameAs.push(url);
541
+ }
542
+ for (const account of profile.verifiedAccounts ?? []) {
543
+ if (account.url && !sameAs.includes(account.url)) sameAs.push(account.url);
544
+ }
545
+ return sameAs;
546
+ }
547
+ function buildHomeLocation(location, s) {
548
+ const addressLocality = location.locality ?? location.city;
549
+ const addressCountry = location.countryCode;
550
+ const hasAddress = Boolean(addressLocality) || Boolean(addressCountry);
551
+ return {
552
+ "@type": "Place",
553
+ name: s(formatLocation(location)),
554
+ ...hasAddress && {
555
+ address: {
556
+ "@type": "PostalAddress",
557
+ ...addressLocality && { addressLocality: s(addressLocality) },
558
+ ...addressCountry && { addressCountry }
559
+ }
560
+ }
561
+ };
562
+ }
563
+ function buildPersonJsonLd(profile, options = {}) {
564
+ const s = options.sanitize ?? identity;
565
+ const baseUrl = normaliseBaseUrl(options.baseUrl);
566
+ const positions = visible(profile.positions);
567
+ const currentPosition = pickPrimaryPosition(positions);
568
+ const knowsAbout = rankKnowsAbout(profile.skills, s);
569
+ const sameAs = buildSameAs(profile);
570
+ const hasCredential = [
571
+ ...visible(profile.education).filter((e) => e.degree).map((e) => ({
572
+ "@type": "EducationalOccupationalCredential",
573
+ credentialCategory: "degree",
574
+ name: [e.degree, e.fieldOfStudy].filter(Boolean).join(" "),
575
+ ...e.institution && {
576
+ recognizedBy: { "@type": "EducationalOrganization", name: s(e.institution) }
577
+ }
578
+ })),
579
+ ...visible(profile.certifications).filter((c) => c.name).map((c) => ({
580
+ "@type": "EducationalOccupationalCredential",
581
+ name: s(c.name),
582
+ ...(c.authority ?? c.issuingOrg) && {
583
+ recognizedBy: {
584
+ "@type": "Organization",
585
+ name: s(c.authority ?? c.issuingOrg)
586
+ }
587
+ },
588
+ ...c.credentialUrl && { url: c.credentialUrl }
589
+ }))
590
+ ];
591
+ const givenTrimmed = profile.givenName?.trim();
592
+ const familyTrimmed = profile.familyName?.trim();
593
+ const structuredName = givenTrimmed && familyTrimmed ? `${givenTrimmed} ${familyTrimmed}` : void 0;
594
+ const awards = visible(profile.honors).filter((h) => h.title).map((h) => s(h.title));
595
+ const languages = visible(profile.languages).filter((l) => l.language).map((l) => l.language);
596
+ return {
597
+ "@context": "https://schema.org",
598
+ "@type": "Person",
599
+ name: s(structuredName ?? profile.displayName ?? profile.handle),
600
+ ...givenTrimmed && { givenName: s(givenTrimmed) },
601
+ ...familyTrimmed && { familyName: s(familyTrimmed) },
602
+ jobTitle: hasMeaningfulText(profile.headline) ? s(profile.headline) : currentPosition?.title ? s(currentPosition.title) : void 0,
603
+ description: hasMeaningfulText(profile.about) ? s(profile.about) : void 0,
604
+ url: `${baseUrl}/p/${profile.handle}`,
605
+ image: profile.avatar ?? void 0,
606
+ ...profile.location && { homeLocation: buildHomeLocation(profile.location, s) },
607
+ ...positions.length > 0 && {
608
+ worksFor: positions.filter((p) => p.company).map((p) => ({
609
+ "@type": "Organization",
610
+ name: s(p.company),
611
+ ...p.title && {
612
+ member: {
613
+ "@type": "OrganizationRole",
614
+ roleName: s(p.title),
615
+ ...p.startedAt && { startDate: p.startedAt },
616
+ ...p.endedAt && { endDate: p.endedAt }
617
+ }
618
+ }
619
+ }))
620
+ },
621
+ ...visible(profile.education).length > 0 && {
622
+ alumniOf: visible(profile.education).filter((e) => e.institution).map((e) => ({ "@type": "EducationalOrganization", name: s(e.institution) }))
623
+ },
624
+ ...hasCredential.length > 0 && { hasCredential },
625
+ ...visible(profile.volunteering).length > 0 && {
626
+ memberOf: visible(profile.volunteering).filter((v) => v.organization).map((v) => ({
627
+ "@type": "OrganizationRole",
628
+ memberOf: { "@type": "Organization", name: s(v.organization) },
629
+ ...v.role && { roleName: s(v.role) },
630
+ ...v.startDate && { startDate: v.startDate },
631
+ ...v.endDate && { endDate: v.endDate }
632
+ }))
633
+ },
634
+ ...awards.length > 0 && { award: awards },
635
+ ...languages.length > 0 && { knowsLanguage: languages },
636
+ ...knowsAbout && { knowsAbout },
637
+ ...sameAs.length > 0 && { sameAs }
638
+ };
639
+ }
640
+ var PROFILE_SECTION_HAS_PART = [
641
+ { id: "about", label: "About", populated: (p) => Boolean(p.about && p.headline) },
642
+ { id: "career", label: "Career", populated: (p) => visible(p.positions).length > 0 },
643
+ { id: "education", label: "Education", populated: (p) => visible(p.education).length > 0 },
644
+ { id: "projects", label: "Projects", populated: (p) => (p.projects?.length ?? 0) > 0 },
645
+ {
646
+ id: "credentials",
647
+ label: "Credentials",
648
+ populated: (p) => visible(p.certifications).length > 0
649
+ },
650
+ {
651
+ id: "publications",
652
+ label: "Publications",
653
+ populated: (p) => (p.publications?.length ?? 0) > 0
654
+ },
655
+ {
656
+ id: "volunteering",
657
+ label: "Volunteering",
658
+ populated: (p) => visible(p.volunteering).length > 0
659
+ },
660
+ { id: "awards", label: "Awards", populated: (p) => visible(p.honors).length > 0 },
661
+ { id: "languages", label: "Languages", populated: (p) => visible(p.languages).length > 0 },
662
+ { id: "skills", label: "Skills", populated: (p) => visible(p.skills).length > 0 },
663
+ {
664
+ id: "other-profiles",
665
+ label: "Other profiles",
666
+ populated: (p) => (p.externalAccounts?.length ?? 0) > 0
667
+ }
668
+ ];
669
+ function buildProfilePageJsonLd(profile, options = {}) {
670
+ const person = buildPersonJsonLd(profile, options);
671
+ const { "@context": _context, ...personWithoutContext } = person;
672
+ const url = `${normaliseBaseUrl(options.baseUrl)}/p/${profile.handle}`;
673
+ const hasPart = PROFILE_SECTION_HAS_PART.filter((section) => section.populated(profile)).map(
674
+ (section) => ({
675
+ "@type": "WebPageElement",
676
+ name: section.label,
677
+ url: `${url}#${section.id}`
678
+ })
679
+ );
680
+ return {
681
+ "@context": "https://schema.org",
682
+ "@type": "ProfilePage",
683
+ url,
684
+ ...profile.updatedAt && { dateModified: profile.updatedAt },
685
+ mainEntity: personWithoutContext,
686
+ ...hasPart.length > 0 && { hasPart }
687
+ };
688
+ }
689
+ function buildBreadcrumbListJsonLd(profile, options = {}) {
690
+ const s = options.sanitize ?? identity;
691
+ const baseUrl = normaliseBaseUrl(options.baseUrl);
692
+ const name = s(profile.displayName ?? profile.handle);
693
+ return {
694
+ "@context": "https://schema.org",
695
+ "@type": "BreadcrumbList",
696
+ itemListElement: [
697
+ { "@type": "ListItem", position: 1, name: "Sifa", item: `${baseUrl}/` },
698
+ {
699
+ "@type": "ListItem",
700
+ position: 2,
701
+ name,
702
+ item: `${baseUrl}/p/${profile.handle}`
703
+ }
704
+ ]
705
+ };
706
+ }
707
+
708
+ // src/format/talk-slug.ts
709
+ var MAX_SLUG_LENGTH = 60;
710
+ var COMBINING_MARKS = /[̀-ͯ]/g;
711
+ function slugifyTitle(title) {
712
+ const slug = title.normalize("NFKD").replace(COMBINING_MARKS, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
713
+ return slug.slice(0, MAX_SLUG_LENGTH).replace(/-+$/g, "");
714
+ }
715
+ function buildTalkSlug(title, rkey) {
716
+ const slug = slugifyTitle(title);
717
+ return slug ? `${slug}-${rkey}` : rkey;
718
+ }
719
+
720
+ // src/jsonld/works.ts
721
+ var DOI_RESOLVER = "https://doi.org/";
722
+ var ORCID_RESOLVER = "https://orcid.org/";
723
+ var identity2 = (input) => input;
724
+ function authorNode(author, baseUrl, s) {
725
+ return {
726
+ "@type": "Person",
727
+ name: s(author.displayName ?? author.handle),
728
+ url: profileUrl(baseUrl, author.handle)
729
+ };
730
+ }
731
+ function confirmedActorNodes(actors, baseUrl, s) {
732
+ return (actors ?? []).filter((a) => a.confirmed === true && Boolean(a.handle)).map((a) => ({
733
+ "@type": "Person",
734
+ name: s(a.displayName ?? a.handle),
735
+ url: profileUrl(baseUrl, a.handle)
736
+ }));
737
+ }
738
+ function visible2(items) {
739
+ return filterHidden(items ? [...items] : void 0);
740
+ }
741
+ var ATTENDANCE_MODE = {
742
+ "community.lexicon.calendar.event#inperson": "https://schema.org/OfflineEventAttendanceMode",
743
+ "community.lexicon.calendar.event#virtual": "https://schema.org/OnlineEventAttendanceMode",
744
+ "community.lexicon.calendar.event#hybrid": "https://schema.org/MixedEventAttendanceMode"
745
+ };
746
+ var EVENT_STATUS = {
747
+ "community.lexicon.calendar.event#scheduled": "https://schema.org/EventScheduled",
748
+ "community.lexicon.calendar.event#cancelled": "https://schema.org/EventCancelled",
749
+ "community.lexicon.calendar.event#postponed": "https://schema.org/EventPostponed",
750
+ "community.lexicon.calendar.event#rescheduled": "https://schema.org/EventRescheduled"
751
+ };
752
+ var LINK_SLIDES = "id.sifa.defs#linkSlides";
753
+ var LINK_RECORDING = "id.sifa.defs#linkRecording";
754
+ function lookup(table, key) {
755
+ if (!key) return void 0;
756
+ return Object.prototype.hasOwnProperty.call(table, key) ? table[key] : void 0;
757
+ }
758
+ function deliveryPlace(delivery, s) {
759
+ const addressLocality = delivery.locationLocality ?? void 0;
760
+ const addressRegion = delivery.locationRegion ?? void 0;
761
+ const addressCountry = delivery.countryCode ?? void 0;
762
+ if (addressLocality || addressRegion || addressCountry) {
763
+ return {
764
+ "@type": "Place",
765
+ address: {
766
+ "@type": "PostalAddress",
767
+ ...addressLocality && { addressLocality: s(addressLocality) },
768
+ ...addressRegion && { addressRegion: s(addressRegion) },
769
+ ...addressCountry && { addressCountry }
770
+ }
771
+ };
772
+ }
773
+ if (delivery.location) {
774
+ return { "@type": "Place", name: s(delivery.location) };
775
+ }
776
+ return void 0;
777
+ }
778
+ function linkOfType(links, type) {
779
+ return links?.find((l) => l.type === type)?.uri;
780
+ }
781
+ function buildPresentationJsonLd(presentation, author, options = {}) {
782
+ const s = options.sanitize ?? identity2;
783
+ const baseUrl = normaliseBaseUrl(options.baseUrl);
784
+ const speaker = authorNode(author, baseUrl, s);
785
+ const events = visible2(presentation.deliveries).map((delivery) => {
786
+ const place = deliveryPlace(delivery, s);
787
+ const recording = linkOfType(delivery.links, LINK_RECORDING);
788
+ const slides = linkOfType(delivery.links, LINK_SLIDES) ?? linkOfType(presentation.links, LINK_SLIDES);
789
+ return {
790
+ "@type": "Event",
791
+ name: s(delivery.eventName ?? delivery.title ?? presentation.title),
792
+ ...delivery.date && { startDate: delivery.date },
793
+ ...place && { location: place },
794
+ ...lookup(ATTENDANCE_MODE, delivery.mode) && {
795
+ eventAttendanceMode: lookup(ATTENDANCE_MODE, delivery.mode)
796
+ },
797
+ ...lookup(EVENT_STATUS, delivery.status) && {
798
+ eventStatus: lookup(EVENT_STATUS, delivery.status)
799
+ },
800
+ performer: [speaker, ...confirmedActorNodes(delivery.coSpeakers, baseUrl, s)],
801
+ ...recording && { recordedIn: { "@type": "VideoObject", url: recording } },
802
+ ...slides && {
803
+ workFeatured: { "@type": "PresentationDigitalDocument", url: slides }
804
+ }
805
+ };
806
+ });
807
+ return {
808
+ "@context": "https://schema.org",
809
+ "@type": "PresentationDigitalDocument",
810
+ name: s(presentation.title),
811
+ ...presentation.description && { abstract: s(presentation.description) },
812
+ ...presentation.duration && { timeRequired: `PT${presentation.duration.minMinutes}M` },
813
+ ...presentation.coverImageUrl && { image: presentation.coverImageUrl },
814
+ author: speaker,
815
+ url: `${baseUrl}/p/${author.handle}/talk/${buildTalkSlug(presentation.title, presentation.rkey)}`,
816
+ ...events.length > 0 && { subjectOf: events }
817
+ };
818
+ }
819
+ function bareDoi(doi) {
820
+ return doi.replace(/^https?:\/\/(dx\.)?doi\.org\//i, "").replace(/^doi:/i, "");
821
+ }
822
+ function buildPublicationJsonLd(publication, author, options = {}) {
823
+ const s = options.sanitize ?? identity2;
824
+ const baseUrl = normaliseBaseUrl(options.baseUrl);
825
+ const authors = publication.contributors && publication.contributors.length > 0 ? publication.contributors.map((c) => ({
826
+ "@type": "Person",
827
+ name: s(c.name),
828
+ ...c.handle && { url: profileUrl(baseUrl, c.handle) },
829
+ ...c.orcidId && { sameAs: [`${ORCID_RESOLVER}${c.orcidId}`] }
830
+ })) : [authorNode(author, baseUrl, s)];
831
+ const doi = publication.doi ? bareDoi(publication.doi) : void 0;
832
+ return {
833
+ "@context": "https://schema.org",
834
+ "@type": "ScholarlyArticle",
835
+ name: s(publication.title),
836
+ ...publication.subtitle && { alternativeHeadline: s(publication.subtitle) },
837
+ ...publication.description && { abstract: s(publication.description) },
838
+ ...publication.publisher && {
839
+ publisher: { "@type": "Organization", name: s(publication.publisher) }
840
+ },
841
+ ...publication.date && { datePublished: publication.date },
842
+ ...publication.url && { url: publication.url },
843
+ author: authors,
844
+ ...doi && {
845
+ identifier: { "@type": "PropertyValue", propertyID: "DOI", value: doi },
846
+ sameAs: [`${DOI_RESOLVER}${doi}`]
847
+ }
848
+ };
849
+ }
850
+ function buildCourseJsonLd(course, options = {}) {
851
+ const s = options.sanitize ?? identity2;
852
+ return {
853
+ "@context": "https://schema.org",
854
+ "@type": "Course",
855
+ name: s(course.name),
856
+ ...course.number && { courseCode: s(course.number) },
857
+ ...course.institution && {
858
+ provider: { "@type": "EducationalOrganization", name: s(course.institution) }
859
+ }
860
+ };
861
+ }
862
+ function buildProjectJsonLd(project, author, options = {}) {
863
+ const s = options.sanitize ?? identity2;
864
+ const baseUrl = normaliseBaseUrl(options.baseUrl);
865
+ const members = confirmedActorNodes(project.members, baseUrl, s);
866
+ return {
867
+ "@context": "https://schema.org",
868
+ "@type": "Project",
869
+ name: s(project.name),
870
+ ...project.description && { description: s(project.description) },
871
+ ...project.url && { url: project.url },
872
+ ...project.startDate && { startDate: project.startDate },
873
+ ...project.endDate && { endDate: project.endDate },
874
+ member: [authorNode(author, baseUrl, s), ...members]
875
+ };
876
+ }
877
+
878
+ exports.TERM_MAPPINGS = TERM_MAPPINGS;
879
+ exports.VOCABULARIES = VOCABULARIES;
880
+ exports.buildBreadcrumbListJsonLd = buildBreadcrumbListJsonLd;
881
+ exports.buildCourseJsonLd = buildCourseJsonLd;
882
+ exports.buildPersonJsonLd = buildPersonJsonLd;
883
+ exports.buildPresentationJsonLd = buildPresentationJsonLd;
884
+ exports.buildProfilePageJsonLd = buildProfilePageJsonLd;
885
+ exports.buildProjectJsonLd = buildProjectJsonLd;
886
+ exports.buildPublicationJsonLd = buildPublicationJsonLd;
887
+ exports.expandCurie = expandCurie;
888
+ exports.isDeliberatelyUnmapped = isDeliberatelyUnmapped;
889
+ exports.mappingsForLexicon = mappingsForLexicon;
890
+ //# sourceMappingURL=index.cjs.map
891
+ //# sourceMappingURL=index.cjs.map