@singi-labs/sifa-sdk 0.19.94 → 0.19.96

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/README.md CHANGED
@@ -27,16 +27,17 @@ Published publicly so third-party developers can build their own AT Protocol cli
27
27
 
28
28
  ## What this package contains
29
29
 
30
- | Area | What it provides |
31
- | ----------- | ------------------------------------------------------------------------------------- |
32
- | Types | TypeScript types for Sifa data structures, generated from `sifa-lexicons` |
33
- | Schemas | Zod schemas mirroring lexicon constraints for runtime validation |
34
- | Query layer | TanStack Query keys, fetchers, and React hooks for calling `sifa-api` |
35
- | ATproto | Wrapper around `@atproto/api` that accepts an authenticated agent |
36
- | Format | Pure formatters for dates, locations, profile completeness |
37
- | Logic | Business-logic predicates (display-only; server-side trust logic lives in `sifa-api`) |
38
- | Taxonomy | Constants and enums (continents, industries, skill categories, activity tiers) |
39
- | Tokens | Sifa-brand design tokens, exported via `@singi-labs/sifa-sdk/tokens` (optional) |
30
+ | Area | What it provides |
31
+ | ----------- | ------------------------------------------------------------------------------------------------------- |
32
+ | Types | TypeScript types for Sifa data structures, generated from `sifa-lexicons` |
33
+ | Schemas | Zod schemas mirroring lexicon constraints for runtime validation |
34
+ | Query layer | TanStack Query keys, fetchers, and React hooks for calling `sifa-api` |
35
+ | ATproto | Wrapper around `@atproto/api` that accepts an authenticated agent |
36
+ | Format | Pure formatters for dates, locations, profile completeness |
37
+ | Logic | Business-logic predicates (display-only; server-side trust logic lives in `sifa-api`) |
38
+ | Taxonomy | Constants and enums (continents, industries, skill categories, activity tiers) |
39
+ | Tokens | Sifa-brand design tokens, exported via `@singi-labs/sifa-sdk/tokens` (optional) |
40
+ | Testing | Anonymized profile responses and sample export details, via `@singi-labs/sifa-sdk/testing` (tests only) |
40
41
 
41
42
  ---
42
43
 
@@ -0,0 +1,79 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Private contact and personal details for exports: email, phone, postal
5
+ * address, driver's license, right to work and nationality.
6
+ *
7
+ * Sifa never stores these and never writes them to the owner's PDS, where they
8
+ * would be public. The owner types them on the export page, the browser keeps
9
+ * them, and they go only into the files the owner downloads. This module holds
10
+ * the shape, the limits and the pick rule, so the export page and the server
11
+ * that builds a funder CV agree on them.
12
+ */
13
+
14
+ /** Longest value accepted per field. 254 is the longest valid email address. */
15
+ declare const EXPORT_CONTACT_LIMITS: {
16
+ readonly email: 254;
17
+ readonly phone: 40;
18
+ readonly address: 500;
19
+ readonly driversLicense: 60;
20
+ readonly rightToWork: 200;
21
+ readonly nationality: 100;
22
+ };
23
+ /** The contact details that go into an export. Absent keys are left out. */
24
+ interface ExportContact {
25
+ readonly email?: string;
26
+ readonly phone?: string;
27
+ /** Free text; lines are separated by `\n`. */
28
+ readonly address?: string;
29
+ /** License categories, e.g. "B, BE". */
30
+ readonly driversLicense?: string;
31
+ /** e.g. "EU citizen, no sponsorship needed". */
32
+ readonly rightToWork?: string;
33
+ readonly nationality?: string;
34
+ }
35
+ /** What the owner has typed, plus which fields they chose to include. */
36
+ interface ExportContactDraft {
37
+ readonly email?: string;
38
+ readonly phone?: string;
39
+ readonly address?: string;
40
+ readonly driversLicense?: string;
41
+ readonly rightToWork?: string;
42
+ readonly nationality?: string;
43
+ readonly includeEmail?: boolean;
44
+ readonly includePhone?: boolean;
45
+ readonly includeAddress?: boolean;
46
+ readonly includeDriversLicense?: boolean;
47
+ readonly includeRightToWork?: boolean;
48
+ readonly includeNationality?: boolean;
49
+ }
50
+ /**
51
+ * Validates a picked contact. Only lengths are checked: phone numbers and
52
+ * addresses vary too much between countries, and a wrong-looking email is a
53
+ * warning for the owner, not a reason to refuse the export.
54
+ */
55
+ declare const exportContactSchema: z.ZodObject<{
56
+ email: z.ZodOptional<z.ZodString>;
57
+ phone: z.ZodOptional<z.ZodString>;
58
+ address: z.ZodOptional<z.ZodString>;
59
+ driversLicense: z.ZodOptional<z.ZodString>;
60
+ rightToWork: z.ZodOptional<z.ZodString>;
61
+ nationality: z.ZodOptional<z.ZodString>;
62
+ }, z.core.$strict>;
63
+ /**
64
+ * The fields to put in an export: the included ones that are not blank, run
65
+ * through {@link normalizeExportContact}.
66
+ */
67
+ declare function pickExportContact(draft: ExportContactDraft): ExportContact;
68
+ /**
69
+ * Drops blank fields and tidies the rest. Every field but the address becomes
70
+ * one line with single spaces. An address keeps its line breaks but loses blank lines and the
71
+ * spaces around each line. Each field is cut at its {@link EXPORT_CONTACT_LIMITS}
72
+ * length. The emitters call this too, so a caller that skips
73
+ * {@link pickExportContact} and the schema gets the same bounded output.
74
+ */
75
+ declare function normalizeExportContact(contact: ExportContact): ExportContact;
76
+ /** A loose shape check for a non-blocking "check this address" hint. */
77
+ declare function looksLikeEmail(value: string): boolean;
78
+
79
+ export { type ExportContact as E, EXPORT_CONTACT_LIMITS as a, type ExportContactDraft as b, exportContactSchema as e, looksLikeEmail as l, normalizeExportContact as n, pickExportContact as p };
@@ -0,0 +1,79 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Private contact and personal details for exports: email, phone, postal
5
+ * address, driver's license, right to work and nationality.
6
+ *
7
+ * Sifa never stores these and never writes them to the owner's PDS, where they
8
+ * would be public. The owner types them on the export page, the browser keeps
9
+ * them, and they go only into the files the owner downloads. This module holds
10
+ * the shape, the limits and the pick rule, so the export page and the server
11
+ * that builds a funder CV agree on them.
12
+ */
13
+
14
+ /** Longest value accepted per field. 254 is the longest valid email address. */
15
+ declare const EXPORT_CONTACT_LIMITS: {
16
+ readonly email: 254;
17
+ readonly phone: 40;
18
+ readonly address: 500;
19
+ readonly driversLicense: 60;
20
+ readonly rightToWork: 200;
21
+ readonly nationality: 100;
22
+ };
23
+ /** The contact details that go into an export. Absent keys are left out. */
24
+ interface ExportContact {
25
+ readonly email?: string;
26
+ readonly phone?: string;
27
+ /** Free text; lines are separated by `\n`. */
28
+ readonly address?: string;
29
+ /** License categories, e.g. "B, BE". */
30
+ readonly driversLicense?: string;
31
+ /** e.g. "EU citizen, no sponsorship needed". */
32
+ readonly rightToWork?: string;
33
+ readonly nationality?: string;
34
+ }
35
+ /** What the owner has typed, plus which fields they chose to include. */
36
+ interface ExportContactDraft {
37
+ readonly email?: string;
38
+ readonly phone?: string;
39
+ readonly address?: string;
40
+ readonly driversLicense?: string;
41
+ readonly rightToWork?: string;
42
+ readonly nationality?: string;
43
+ readonly includeEmail?: boolean;
44
+ readonly includePhone?: boolean;
45
+ readonly includeAddress?: boolean;
46
+ readonly includeDriversLicense?: boolean;
47
+ readonly includeRightToWork?: boolean;
48
+ readonly includeNationality?: boolean;
49
+ }
50
+ /**
51
+ * Validates a picked contact. Only lengths are checked: phone numbers and
52
+ * addresses vary too much between countries, and a wrong-looking email is a
53
+ * warning for the owner, not a reason to refuse the export.
54
+ */
55
+ declare const exportContactSchema: z.ZodObject<{
56
+ email: z.ZodOptional<z.ZodString>;
57
+ phone: z.ZodOptional<z.ZodString>;
58
+ address: z.ZodOptional<z.ZodString>;
59
+ driversLicense: z.ZodOptional<z.ZodString>;
60
+ rightToWork: z.ZodOptional<z.ZodString>;
61
+ nationality: z.ZodOptional<z.ZodString>;
62
+ }, z.core.$strict>;
63
+ /**
64
+ * The fields to put in an export: the included ones that are not blank, run
65
+ * through {@link normalizeExportContact}.
66
+ */
67
+ declare function pickExportContact(draft: ExportContactDraft): ExportContact;
68
+ /**
69
+ * Drops blank fields and tidies the rest. Every field but the address becomes
70
+ * one line with single spaces. An address keeps its line breaks but loses blank lines and the
71
+ * spaces around each line. Each field is cut at its {@link EXPORT_CONTACT_LIMITS}
72
+ * length. The emitters call this too, so a caller that skips
73
+ * {@link pickExportContact} and the schema gets the same bounded output.
74
+ */
75
+ declare function normalizeExportContact(contact: ExportContact): ExportContact;
76
+ /** A loose shape check for a non-blocking "check this address" hint. */
77
+ declare function looksLikeEmail(value: string): boolean;
78
+
79
+ export { type ExportContact as E, EXPORT_CONTACT_LIMITS as a, type ExportContactDraft as b, exportContactSchema as e, looksLikeEmail as l, normalizeExportContact as n, pickExportContact as p };
package/dist/index.cjs CHANGED
@@ -6047,6 +6047,10 @@ function completenessScore(c) {
6047
6047
  function completenessPercent(c) {
6048
6048
  return Math.round(completenessScore(c) / COMPLETENESS_MAX_SCORE * 100);
6049
6049
  }
6050
+ var OPTIONAL_COMPLETENESS_SIGNALS = ["certification"];
6051
+ function isOptionalCompletenessSignal(signal) {
6052
+ return OPTIONAL_COMPLETENESS_SIGNALS.some((optional) => optional === signal);
6053
+ }
6050
6054
 
6051
6055
  // src/logic/profile-dimensions.ts
6052
6056
  var DIMENSIONS_MAX_SCORE = 6;
@@ -7692,7 +7696,7 @@ function describeSifaRecord(collection, value) {
7692
7696
  }
7693
7697
 
7694
7698
  // src/index.ts
7695
- var SIFA_SDK_VERSION = "0.19.94";
7699
+ var SIFA_SDK_VERSION = "0.19.96";
7696
7700
 
7697
7701
  exports.ACTIVITY_TIERS = ACTIVITY_TIERS;
7698
7702
  exports.ACTIVITY_VERBS = ACTIVITY_VERBS;
@@ -7774,6 +7778,7 @@ exports.OPEN_TO_TOKENS = OPEN_TO_TOKENS;
7774
7778
  exports.OPEN_TO_TOKEN_LABELS = OPEN_TO_TOKEN_LABELS;
7775
7779
  exports.OPEN_TO_TOKEN_TO_VALUE = OPEN_TO_TOKEN_TO_VALUE;
7776
7780
  exports.OPEN_TO_VALUE_TO_TOKEN = OPEN_TO_VALUE_TO_TOKEN;
7781
+ exports.OPTIONAL_COMPLETENESS_SIGNALS = OPTIONAL_COMPLETENESS_SIGNALS;
7777
7782
  exports.OrgEmploymentAttestationRecordSchema = OrgEmploymentAttestationRecordSchema;
7778
7783
  exports.OrgProfileRecordSchema = OrgProfileRecordSchema;
7779
7784
  exports.PLATFORM_LABELS = PLATFORM_LABELS;
@@ -7936,6 +7941,7 @@ exports.isKnownPlatform = isKnownPlatform;
7936
7941
  exports.isKnownVerificationProvider = isKnownVerificationProvider;
7937
7942
  exports.isLinked = isLinked;
7938
7943
  exports.isOnBehalfOfApplicable = isOnBehalfOfApplicable;
7944
+ exports.isOptionalCompletenessSignal = isOptionalCompletenessSignal;
7939
7945
  exports.isPseudoEmployer = isPseudoEmployer;
7940
7946
  exports.isRegistrableDomainHandle = isRegistrableDomainHandle;
7941
7947
  exports.isRelationalActivity = isRelationalActivity;