gdc-common-utils-ts 2.3.19 → 2.3.21

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.
@@ -1,12 +1,22 @@
1
+ /**
2
+ * @deprecated Animal-card vocabulary is owned by the consuming product SDK.
3
+ * Retained only so consumers of 2.3.x can migrate without a breaking removal.
4
+ */
1
5
  export declare const AnimalSubjectKinds: Readonly<{
2
6
  readonly Animal: "animal";
3
7
  }>;
8
+ /**
9
+ * @deprecated Use the species registry from the consuming product SDK.
10
+ * NCBI Taxonomy identifiers are external identifiers and are not a GDC model.
11
+ */
4
12
  export declare const NcbiTaxonomy: Readonly<{
5
13
  readonly Dog: "9615";
6
14
  readonly Cat: "9685";
7
15
  readonly Horse: "9796";
8
16
  }>;
17
+ /** @deprecated Import the taxonomy identifier type from the product SDK. */
9
18
  export type NcbiTaxonomyId = string;
19
+ /** @deprecated Import the animal onboarding input from the product SDK. */
10
20
  export type AnimalOnboardingInput = Readonly<{
11
21
  subjectId: string;
12
22
  cardDidWeb: string;
@@ -20,8 +30,11 @@ export type AnimalOnboardingInput = Readonly<{
20
30
  controllerTelephone?: string;
21
31
  sector?: string;
22
32
  }>;
33
+ /** @deprecated Import the animal onboarding claims type from the product SDK. */
23
34
  export type AnimalOnboardingClaims = Readonly<Record<string, string>>;
24
35
  /**
36
+ * @deprecated Use the taxonomy URI builder from the product SDK.
37
+ *
25
38
  * Builds the canonical OBO URI for one NCBI Taxonomy numeric identifier.
26
39
  *
27
40
  * The URI is public taxonomy metadata, not an animal identifier. Callers must
@@ -30,6 +43,9 @@ export type AnimalOnboardingClaims = Readonly<Record<string, string>>;
30
43
  */
31
44
  export declare function buildNcbiTaxonomyUri(id: NcbiTaxonomyId): string;
32
45
  /**
46
+ * @deprecated Use the animal onboarding builder from the product SDK. This
47
+ * compatibility implementation will be removed in the next major release.
48
+ *
33
49
  * Projects one controller-authorized animal card request to the existing
34
50
  * schema.org individual-organization claim envelope.
35
51
  *
@@ -1,14 +1,24 @@
1
1
  import { ClaimsOrganizationSchemaorg, ClaimsServiceSchemaorg } from '../constants/schemaorg.js';
2
2
  import { DataspaceSectors } from '../constants/sectors.js';
3
+ /**
4
+ * @deprecated Animal-card vocabulary is owned by the consuming product SDK.
5
+ * Retained only so consumers of 2.3.x can migrate without a breaking removal.
6
+ */
3
7
  export const AnimalSubjectKinds = Object.freeze({
4
8
  Animal: 'animal',
5
9
  });
10
+ /**
11
+ * @deprecated Use the species registry from the consuming product SDK.
12
+ * NCBI Taxonomy identifiers are external identifiers and are not a GDC model.
13
+ */
6
14
  export const NcbiTaxonomy = Object.freeze({
7
15
  Dog: '9615',
8
16
  Cat: '9685',
9
17
  Horse: '9796',
10
18
  });
11
19
  /**
20
+ * @deprecated Use the taxonomy URI builder from the product SDK.
21
+ *
12
22
  * Builds the canonical OBO URI for one NCBI Taxonomy numeric identifier.
13
23
  *
14
24
  * The URI is public taxonomy metadata, not an animal identifier. Callers must
@@ -26,6 +36,9 @@ export function buildNcbiTaxonomyUri(id) {
26
36
  return `http://purl.obolibrary.org/obo/NCBITaxon_${normalized}`;
27
37
  }
28
38
  /**
39
+ * @deprecated Use the animal onboarding builder from the product SDK. This
40
+ * compatibility implementation will be removed in the next major release.
41
+ *
29
42
  * Projects one controller-authorized animal card request to the existing
30
43
  * schema.org individual-organization claim envelope.
31
44
  *
@@ -2,6 +2,7 @@ export type ParsedActor = {
2
2
  /**
3
3
  * The token subject / authenticated actor identifier (as provided in the token request).
4
4
  * Examples:
5
+ * - did:web:api.acme.org:member:z6MksExampleHashedMemberId:ISCO-08|2211
5
6
  * - did:web:api.acme.org:employee:z6MksExampleHashedEmployeeId:ISCO-08|2211
6
7
  * - did:web:api.acme.org:employee:z6MksExampleHashedEmployeeId:ISCO-08|2211:<device-uuid>
7
8
  * - did:web:api.acme.org:employee:doctor1@acme.org:ISCO-08|2211
@@ -10,10 +11,15 @@ export type ParsedActor = {
10
11
  * - did:web:api.acme.org:family:<id>:v3-RoleCode|CHILD:<device-uuid>
11
12
  */
12
13
  sub: string;
13
- /** The actor identifier (employee hashed-id/email token, familyId, or raw email). */
14
+ /** The terminal member identifier (hashed email/phone, family id, or raw email). */
14
15
  identifier?: string;
15
16
  /** The employee role code if present (e.g. "ISCO-08|2211"). */
16
17
  role?: string;
18
+ /**
19
+ * Membership domain inferred from the terminal role contract, not from a
20
+ * provider-specific `member`/`employee` path label.
21
+ */
22
+ memberKind?: 'organization' | 'individual';
17
23
  /** The base organization did:web if `sub` is did:web (e.g. "did:web:api.acme.org"). */
18
24
  organization?: string;
19
25
  };
@@ -11,20 +11,40 @@ export function parseActorFromSub(sub) {
11
11
  const host = after.split(':')[0];
12
12
  if (host)
13
13
  parsed.organization = `did:web:${host}`;
14
- // Extract email and role from endpoint-style DID shapes:
15
- // did:web:<host>:(employee|family):<id>:<roleSystem>|<roleCode>[:<uuid>]
14
+ // Member vocabulary is provider-specific (`member`, `employee`, `family`,
15
+ // `individual-member`, ...). The interoperable identity tuple is the
16
+ // terminal `<identifier>:<role-system>|<role-code>` pair, optionally
17
+ // followed by a device id. Do not make consent matching depend on a path
18
+ // label chosen by a hosted or external DID provider.
16
19
  const parts = after.split(':');
17
- const employeeIdx = parts.indexOf('employee');
18
- const familyIdx = parts.indexOf('family');
19
- const idIdx = employeeIdx >= 0 ? employeeIdx + 1 : familyIdx >= 0 ? familyIdx + 1 : -1;
20
+ const roleIdx = parts.findIndex((part) => {
21
+ try {
22
+ return decodeURIComponent(part).includes('|');
23
+ }
24
+ catch {
25
+ return part.includes('|');
26
+ }
27
+ });
28
+ const hasRoleLabel = roleIdx > 0 && parts[roleIdx - 1].toLowerCase() === 'role';
29
+ const idIdx = roleIdx > 0 ? roleIdx - (hasRoleLabel ? 2 : 1) : -1;
20
30
  const identifier = idIdx >= 0 ? parts[idIdx] : undefined;
21
31
  if (identifier) {
22
32
  parsed.identifier = identifier.includes('@') ? identifier.toLowerCase() : identifier;
23
33
  }
24
- if (idIdx >= 0 && parts.length > idIdx + 1) {
25
- const roleCandidate = parts[idIdx + 1];
26
- if (roleCandidate && roleCandidate.includes('|'))
27
- parsed.role = roleCandidate;
34
+ if (roleIdx >= 0) {
35
+ const encodedRole = parts[roleIdx];
36
+ try {
37
+ parsed.role = decodeURIComponent(encodedRole);
38
+ }
39
+ catch {
40
+ parsed.role = encodedRole;
41
+ }
42
+ const normalizedRole = String(parsed.role || '').trim().toLowerCase();
43
+ const pathLabels = parts.slice(1, Math.max(1, idIdx)).map((part) => part.toLowerCase());
44
+ parsed.memberKind = normalizedRole.startsWith('v3-rolecode|')
45
+ || pathLabels.some((part) => part === 'family' || part === 'related-person' || part === 'individual-member')
46
+ ? 'individual'
47
+ : 'organization';
28
48
  }
29
49
  return parsed;
30
50
  }
@@ -54,6 +54,10 @@ export type BuildConsentClaimsSimpleInput = SubjectIdentifierInput & {
54
54
  consentIdentifier?: string;
55
55
  consentDate?: string;
56
56
  decision?: 'permit' | 'deny';
57
+ /** Stable identifier/thread of the permission request that caused this decision. */
58
+ eventBasedOn?: string;
59
+ /** Canonical Communication reference for the permission request being answered. */
60
+ sourceReference?: string;
57
61
  attachmentContentType?: string;
58
62
  attachmentBase64?: string;
59
63
  };
@@ -169,6 +169,12 @@ export function buildConsentClaimsSimple(input, options = {}) {
169
169
  [ClaimConsent.action]: (input.actions || []).join(','),
170
170
  [ClaimConsent.actorIdentifier]: actorIdentifier,
171
171
  [ClaimConsent.actorRole]: input.actorRole,
172
+ ...(String(input.eventBasedOn || '').trim()
173
+ ? { [ClaimConsent.eventBasedOn]: String(input.eventBasedOn).trim() }
174
+ : {}),
175
+ ...(String(input.sourceReference || '').trim()
176
+ ? { [ClaimConsent.sourceReference]: String(input.sourceReference).trim() }
177
+ : {}),
172
178
  [ClaimConsent.attachmentContentType]: input.attachmentContentType || 'application/odrl+json',
173
179
  [ClaimConsent.attachmentData]: input.attachmentBase64 || 'e30=',
174
180
  },
@@ -20,6 +20,13 @@ export type ProfessionalSmartVpPayloadInput = Readonly<{
20
20
  additionalVp?: Record<string, unknown>;
21
21
  additionalPayload?: Record<string, unknown>;
22
22
  }>;
23
+ /** Identity fields read from an already-verified professional credential. */
24
+ export type ProfessionalCredentialSummary = Readonly<{
25
+ actorDid: string;
26
+ role: string;
27
+ issuerDid?: string;
28
+ sameAs: string[];
29
+ }>;
23
30
  /**
24
31
  * Returns the normalized public continuity aliases for one professional
25
32
  * identity VC.
@@ -62,6 +69,16 @@ export declare function getProfessionalIdentityTelephone(input: Readonly<Pick<Pr
62
69
  * @param input Professional identity source values.
63
70
  */
64
71
  export declare function getProfessionalIdentityVC(input: ProfessionalEmployeeCredentialInput): Record<string, unknown>;
72
+ /**
73
+ * Reads the actor and role asserted by one professional credential. Signature
74
+ * and employer/issuer trust verification belongs to the enclosing VP verifier.
75
+ */
76
+ export declare function summarizeProfessionalIdentityCredential(credential: unknown): ProfessionalCredentialSummary | undefined;
77
+ /** Finds the exact actor and role in an already-verified professional VP. */
78
+ export declare function getMatchingProfessionalCredentialFromVpToken(vpToken: string, criteria: Readonly<{
79
+ actorDid: string;
80
+ role: string;
81
+ }>): ProfessionalCredentialSummary | undefined;
65
82
  /**
66
83
  * Backwards-compatible alias kept for existing SMART demo callers.
67
84
  *
@@ -2,6 +2,7 @@ import { ClaimsPersonSchemaorg } from '../constants/schemaorg.js';
2
2
  import { ProfessionalCredentialTypes, W3cCredentialTypes, } from '../constants/verifiable-credentials.js';
3
3
  import { normalizeSameAsHashCsv, normalizeSameAsHashList, normalizeTelephoneHash } from './same-as.js';
4
4
  import { buildUnsignedVpJwt } from './jwt.js';
5
+ import { getVpCredentials } from './vp-token.js';
5
6
  /**
6
7
  * Returns the normalized public continuity aliases for one professional
7
8
  * identity VC.
@@ -84,6 +85,38 @@ export function getProfessionalIdentityVC(input) {
84
85
  ...(input.additionalCredential || {}),
85
86
  };
86
87
  }
88
+ /**
89
+ * Reads the actor and role asserted by one professional credential. Signature
90
+ * and employer/issuer trust verification belongs to the enclosing VP verifier.
91
+ */
92
+ export function summarizeProfessionalIdentityCredential(credential) {
93
+ const source = credential;
94
+ const types = Array.isArray(source?.type) ? source.type.map(String) : [String(source?.type || '')];
95
+ if (!types.includes(ProfessionalCredentialTypes.EmployeeCredential))
96
+ return undefined;
97
+ const subject = source?.credentialSubject || {};
98
+ const actorDid = String(subject.id || '').trim();
99
+ const role = String(subject.hasOccupation || '').trim();
100
+ if (!actorDid || !role)
101
+ return undefined;
102
+ const issuerDid = String(source?.issuer?.id || source?.issuer || '').trim();
103
+ return {
104
+ actorDid,
105
+ role,
106
+ ...(issuerDid ? { issuerDid } : {}),
107
+ sameAs: normalizeSameAsHashList(subject.sameAs),
108
+ };
109
+ }
110
+ /** Finds the exact actor and role in an already-verified professional VP. */
111
+ export function getMatchingProfessionalCredentialFromVpToken(vpToken, criteria) {
112
+ const actorDid = String(criteria.actorDid || '').trim();
113
+ const role = String(criteria.role || '').trim().toLowerCase();
114
+ return getVpCredentials(vpToken)
115
+ .map(summarizeProfessionalIdentityCredential)
116
+ .find((summary) => Boolean(summary
117
+ && summary.actorDid === actorDid
118
+ && summary.role.toLowerCase() === role));
119
+ }
87
120
  /**
88
121
  * Backwards-compatible alias kept for existing SMART demo callers.
89
122
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdc-common-utils-ts",
3
- "version": "2.3.19",
3
+ "version": "2.3.21",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },