gdc-common-utils-ts 1.2.0 → 1.4.1

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 ADDED
@@ -0,0 +1,121 @@
1
+ # gdc-common-utils-ts
2
+
3
+ Shared TypeScript utilities for GDC client and connector code. This package provides low-level primitives for cryptography, DID/DIDComm-related helpers, and the shared models and interfaces used across SDKs.
4
+
5
+ It is intentionally not a full backend orchestration layer.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install gdc-common-utils-ts
11
+ ```
12
+
13
+ ## What It Exports
14
+
15
+ The published package exposes these entry points through `package.json`:
16
+
17
+ - Root: `gdc-common-utils-ts`
18
+ - `gdc-common-utils-ts/AesManager`
19
+ - `gdc-common-utils-ts/CryptographyService`
20
+ - `gdc-common-utils-ts/hmac`
21
+ - `gdc-common-utils-ts/constants`
22
+ - `gdc-common-utils-ts/models`
23
+ - `gdc-common-utils-ts/utils`
24
+ - `gdc-common-utils-ts/interfaces`
25
+ - File-level subpaths under `constants/*`, `models/*`, `utils/*`, and `interfaces/*`
26
+
27
+ ### Root crypto exports
28
+
29
+ The package root re-exports the main crypto helpers:
30
+
31
+ - `AesManager`
32
+ - `CryptographyService`
33
+ - `computeHmacSha256`
34
+ - `computeHmacSha256Base64Url`
35
+
36
+ Example:
37
+
38
+ ```ts
39
+ import { AesManager, CryptographyService, computeHmacSha256Base64Url } from 'gdc-common-utils-ts';
40
+ ```
41
+
42
+ ### Utilities
43
+
44
+ The `utils` export exposes reusable helpers for DID and message handling, such as:
45
+
46
+ - `utils/did` helpers like `generateServiceId`, `normalizeDidWeb`, `createHostedDidWeb`, `buildHostedDidDetails`, and `getBaseUrlFromDidWeb`
47
+ - `utils/jwt`
48
+ - `utils/content`
49
+ - `utils/normalize`
50
+ - `utils/fhir-cid` for recursive FHIR canonicalization + CID generation + `meta.versionId` assignment
51
+ - conversion, formatting, and multibase helpers
52
+
53
+ These helpers support DIDComm-style message construction and related transport/data-shaping workflows.
54
+
55
+ Example:
56
+
57
+ ```ts
58
+ import { normalizeDidWeb, generateServiceId } from 'gdc-common-utils-ts/utils/did';
59
+ import { fhirResourceToCid, assignCidToFhirResourceVersionId } from 'gdc-common-utils-ts/utils/fhir-cid';
60
+ ```
61
+
62
+ ### Models
63
+
64
+ The `models` export contains the shared data shapes used by the SDKs, including:
65
+
66
+ - cryptographic and JOSE shapes such as `aes`, `jwe`, `jws`, `jwt`, and `jwk`
67
+ - DID and DIDComm-related models such as `did`, `comm`, and `verifiable-credential`
68
+ - confidential transport and storage models
69
+ - auth, device, response, issue, and FHIR-oriented models
70
+
71
+ Example:
72
+
73
+ ```ts
74
+ import { JweObject, JwtCompactParts } from 'gdc-common-utils-ts/models';
75
+ ```
76
+
77
+ ### Interfaces
78
+
79
+ The `interfaces` export contains the shared type contracts and cryptography types, including:
80
+
81
+ - `ICryptography`
82
+ - `ICryptoHelper`
83
+ - `IWallet`
84
+ - `Cryptography.types`
85
+ - `MlDsa`
86
+ - `MlKem`
87
+
88
+ Example:
89
+
90
+ ```ts
91
+ import { ICryptography, MlkemPublicJwk } from 'gdc-common-utils-ts/interfaces/Cryptography.types';
92
+ ```
93
+
94
+ ## Auth-Flow Boundaries
95
+
96
+ This package provides primitives, not orchestration.
97
+
98
+ It supports the cryptographic and data-model building blocks needed by higher-level clients, but it does not coordinate the backend auth exchange sequence for:
99
+
100
+ - `/_dcr`
101
+ - `/_code`
102
+ - `/_token`
103
+ - `/_exchange`
104
+
105
+ Those request/response flows belong in connector SDKs and backend orchestration layers.
106
+
107
+ ## Relationship To Other SDKs
108
+
109
+ `gdc-sdk-client-ts` and `dataconv-client-sdk-ts` are consumers of this package, not replacements for it.
110
+
111
+ - Use `gdc-common-utils-ts` when you need shared crypto primitives, DID/DIDComm helpers, and common types
112
+ - Use `gdc-sdk-client-ts` or `dataconv-client-sdk-ts` when you need higher-level client orchestration, transport, or API workflows
113
+
114
+ ## Notes
115
+
116
+ - The package is published as ESM.
117
+ - The `files` field only publishes `dist/`, so source imports should use the documented package entry points rather than local file paths.
118
+
119
+ ## Roadmap and Briefing
120
+ - `BRIEFING_DATASPACE_EN.md`
121
+ - `TODO_ROADMAP.md`
@@ -0,0 +1,44 @@
1
+ /**
2
+ * HL7 role constants shared across GDC projects.
3
+ *
4
+ * Two distinct value sets are provided:
5
+ *
6
+ * 1. v3-PersonalRelationshipRoleType
7
+ * "Who are you in relation to the subject?" (family / social relationship)
8
+ * Source: http://terminology.hl7.org/ValueSet/v3-PersonalRelationshipRoleType
9
+ *
10
+ * 2. v3-RoleCode — legal / functional representative subset
11
+ * "What legal role do you exercise over the subject?" (guardian, attorney…)
12
+ * Source: http://terminology.hl7.org/ValueSet/v3-RoleCode
13
+ * Used as default for non-human subjects (e.g. animal-care sector).
14
+ * Default for animal-care: RESPRSN (Responsible party).
15
+ */
16
+ export type Hl7RoleEntry = {
17
+ code: string;
18
+ display: string;
19
+ definition: string;
20
+ };
21
+ export declare const HL7_CODING_SYSTEM_PERSONAL_RELATIONSHIP = "http://terminology.hl7.org/CodeSystem/v3-PersonalRelationshipRoleType";
22
+ /** Canonical OID alias used in GDC claims (org.hl7.v3.RoleCode covers both sets). */
23
+ export declare const HL7_CLAIMS_CODING_SYSTEM = "org.hl7.v3.RoleCode";
24
+ /**
25
+ * Full ordered list of HL7 v3-PersonalRelationshipRoleType entries.
26
+ * Suitable for relationship pickers in health-sector family registration.
27
+ * Default role: `ONESELF` (patient represents themselves).
28
+ */
29
+ export declare const HL7_PERSONAL_RELATIONSHIP_ROLES: Hl7RoleEntry[];
30
+ export declare const HL7_CODING_SYSTEM_V3_ROLE_CODE = "http://terminology.hl7.org/CodeSystem/v3-RoleCode";
31
+ /**
32
+ * Legal representative / guardian roles from HL7 v3-RoleCode.
33
+ *
34
+ * Used when the owner of an individual record exercises a legal function
35
+ * rather than a personal relationship (e.g. animal-care sector, minors
36
+ * with court-appointed guardian, power of attorney).
37
+ *
38
+ * Default for animal-care sector: `RESPRSN` (Responsible party).
39
+ */
40
+ export declare const HL7_V3_ROLE_CODE_LEGAL_REPRESENTATIVE: Hl7RoleEntry[];
41
+ /** Default role code for animal-care and non-human subjects. */
42
+ export declare const HL7_DEFAULT_ROLE_ANIMAL_CARE = "RESPRSN";
43
+ /** Default role code for health sector (patient self-represents). */
44
+ export declare const HL7_DEFAULT_ROLE_HEALTH = "ONESELF";
@@ -0,0 +1,208 @@
1
+ /**
2
+ * HL7 role constants shared across GDC projects.
3
+ *
4
+ * Two distinct value sets are provided:
5
+ *
6
+ * 1. v3-PersonalRelationshipRoleType
7
+ * "Who are you in relation to the subject?" (family / social relationship)
8
+ * Source: http://terminology.hl7.org/ValueSet/v3-PersonalRelationshipRoleType
9
+ *
10
+ * 2. v3-RoleCode — legal / functional representative subset
11
+ * "What legal role do you exercise over the subject?" (guardian, attorney…)
12
+ * Source: http://terminology.hl7.org/ValueSet/v3-RoleCode
13
+ * Used as default for non-human subjects (e.g. animal-care sector).
14
+ * Default for animal-care: RESPRSN (Responsible party).
15
+ */
16
+ // ---------------------------------------------------------------------------
17
+ // 1. v3-PersonalRelationshipRoleType
18
+ // ---------------------------------------------------------------------------
19
+ export const HL7_CODING_SYSTEM_PERSONAL_RELATIONSHIP = 'http://terminology.hl7.org/CodeSystem/v3-PersonalRelationshipRoleType';
20
+ /** Canonical OID alias used in GDC claims (org.hl7.v3.RoleCode covers both sets). */
21
+ export const HL7_CLAIMS_CODING_SYSTEM = 'org.hl7.v3.RoleCode';
22
+ const PERSONAL_RELATIONSHIP_LIST = [
23
+ { code: 'ONESELF', display: 'self', definition: 'The relationship that a person has with himself or herself.' },
24
+ { code: 'CHILD', display: 'child', definition: 'The player of the role is a child of the scoping entity.' },
25
+ { code: 'CHLDADOPT', display: 'adopted child', definition: 'The player of the role is a child taken into a family through legal means and raised by the scoping person as his or her own child.' },
26
+ { code: 'DAUADOPT', display: 'adopted daughter', definition: 'The player of the role is a female child taken into a family through legal means and raised by the scoping person as his or her own child.' },
27
+ { code: 'SONADOPT', display: 'adopted son', definition: 'The player of the role is a male child taken into a family through legal means and raised by the scoping person as his or her own child.' },
28
+ { code: 'CHLDFOST', display: 'foster child', definition: 'The player of the role is a child receiving parental care and nurture from the scoping person but not related through legal or blood ties.' },
29
+ { code: 'DAUFOST', display: 'foster daughter', definition: 'The player of the role is a female child receiving parental care and nurture from the scoping person but not related through legal or blood ties.' },
30
+ { code: 'SONFOST', display: 'foster son', definition: 'The player of the role is a male child receiving parental care and nurture from the scoping person but not related through legal or blood ties.' },
31
+ { code: 'DAUC', display: 'daughter', definition: 'The player of the role is a female child (of any type) of the scoping entity.' },
32
+ { code: 'DAU', display: 'natural daughter', definition: 'The player of the role is a female offspring of the scoping entity.' },
33
+ { code: 'STPDAU', display: 'stepdaughter', definition: "The player of the role is a daughter of the scoping person's spouse by a previous union." },
34
+ { code: 'NCHILD', display: 'natural child', definition: 'The player of the role is an offspring of the scoping entity as determined by birth.' },
35
+ { code: 'SON', display: 'natural son', definition: 'The player of the role is a male offspring of the scoping entity.' },
36
+ { code: 'SONC', display: 'son', definition: 'The player of the role is a male child (of any type) of the scoping entity.' },
37
+ { code: 'STPSON', display: 'stepson', definition: "The player of the role is a son of the scoping person's spouse by a previous union." },
38
+ { code: 'STPCHLD', display: 'step child', definition: "The player of the role is a child of the scoping person's spouse by a previous union." },
39
+ { code: 'AUNT', display: 'aunt', definition: "The player of the role is a sister of the scoping person's mother or father." },
40
+ { code: 'MAUNT', display: 'maternal aunt', definition: "The player of the role is a biological sister of the scoping person's biological mother." },
41
+ { code: 'PAUNT', display: 'paternal aunt', definition: "The player of the role is a biological sister of the scoping person's biological father." },
42
+ { code: 'COUSN', display: 'cousin', definition: 'The player of the role is a relative of the scoping person descended from a common ancestor, such as a grandparent, by two or more steps in a diverging line.' },
43
+ { code: 'MCOUSN', display: 'maternal cousin', definition: "The player of the role is a biological relative of the scoping person descended from a common ancestor on the player's mother's side." },
44
+ { code: 'PCOUSN', display: 'paternal cousin', definition: "The player of the role is a biological relative of the scoping person descended from a common ancestor on the player's father's side." },
45
+ { code: 'GGRPRN', display: 'great grandparent', definition: "The player of the role is a parent of the scoping person's grandparent." },
46
+ { code: 'GGRFTH', display: 'great grandfather', definition: "The player of the role is the father of the scoping person's grandparent." },
47
+ { code: 'MGGRFTH', display: 'maternal great-grandfather', definition: "The player of the role is the biological father of the scoping person's biological mother's parent." },
48
+ { code: 'PGGRFTH', display: 'paternal great-grandfather', definition: "The player of the role is the biological father of the scoping person's biological father's parent." },
49
+ { code: 'GGRMTH', display: 'great grandmother', definition: "The player of the role is the mother of the scoping person's grandparent." },
50
+ { code: 'MGGRMTH', display: 'maternal great-grandmother', definition: "The player of the role is the biological mother of the scoping person's biological mother's parent." },
51
+ { code: 'PGGRMTH', display: 'paternal great-grandmother', definition: "The player of the role is the biological mother of the scoping person's biological father's parent." },
52
+ { code: 'MGGRPRN', display: 'maternal great-grandparent', definition: "The player of the role is a biological parent of the scoping person's biological mother's parent." },
53
+ { code: 'PGGRPRN', display: 'paternal great-grandparent', definition: "The player of the role is a biological parent of the scoping person's biological father's parent." },
54
+ { code: 'GRNDCHILD', display: 'grandchild', definition: "The player of the role is a child of the scoping person's son or daughter." },
55
+ { code: 'GRNDDAU', display: 'granddaughter', definition: "The player of the role is a daughter of the scoping person's son or daughter." },
56
+ { code: 'GRNDSON', display: 'grandson', definition: "The player of the role is a son of the scoping person's son or daughter." },
57
+ { code: 'GRPRN', display: 'grandparent', definition: "The player of the role is a parent of the scoping person's mother or father." },
58
+ { code: 'GRFTH', display: 'grandfather', definition: "The player of the role is the father of the scoping person's mother or father." },
59
+ { code: 'MGRFTH', display: 'maternal grandfather', definition: "The player of the role is the biological father of the scoping person's biological mother." },
60
+ { code: 'PGRFTH', display: 'paternal grandfather', definition: "The player of the role is the biological father of the scoping person's biological father." },
61
+ { code: 'GRMTH', display: 'grandmother', definition: "The player of the role is the mother of the scoping person's mother or father." },
62
+ { code: 'MGRMTH', display: 'maternal grandmother', definition: "The player of the role is the biological mother of the scoping person's biological mother." },
63
+ { code: 'PGRMTH', display: 'paternal grandmother', definition: "The player of the role is the biological mother of the scoping person's biological father." },
64
+ { code: 'MGRPRN', display: 'maternal grandparent', definition: "The player of the role is the biological parent of the scoping person's biological mother." },
65
+ { code: 'PGRPRN', display: 'paternal grandparent', definition: "The player of the role is the biological parent of the scoping person's biological father." },
66
+ { code: 'CHLDINLAW', display: 'child-in-law', definition: "The player of the role is the spouse of the scoping person's child." },
67
+ { code: 'DAUINLAW', display: 'daughter in-law', definition: "The player of the role is the wife of the scoping person's son." },
68
+ { code: 'SONINLAW', display: 'son in-law', definition: "The player of the role is the husband of the scoping person's daughter." },
69
+ { code: 'PRNINLAW', display: 'parent in-law', definition: "The player of the role is the parent of the scoping person's husband or wife." },
70
+ { code: 'FTHINLAW', display: 'father-in-law', definition: "The player of the role is the father of the scoping person's husband or wife." },
71
+ { code: 'MTHINLAW', display: 'mother-in-law', definition: "The player of the role is the mother of the scoping person's husband or wife." },
72
+ { code: 'SIBINLAW', display: 'sibling in-law', definition: "The player of the role is a sibling of the scoping person's spouse, or the spouse of the scoping person's sibling, or the spouse of a sibling of the scoping person's spouse." },
73
+ { code: 'BROINLAW', display: 'brother-in-law', definition: "The player of the role is a brother of the scoping person's spouse, or the husband of the scoping person's sister, or the husband of a sister of the scoping person's spouse." },
74
+ { code: 'SISINLAW', display: 'sister-in-law', definition: "The player of the role is a sister of the scoping person's spouse, or the wife of the scoping person's brother, or the wife of a brother of the scoping person's spouse." },
75
+ { code: 'NIENEPH', display: 'niece/nephew', definition: "The player of the role is a child of the scoping person's brother or sister or of the brother or sister of the scoping person's spouse." },
76
+ { code: 'NEPHEW', display: 'nephew', definition: "The player of the role is a son of the scoping person's brother or sister or of the brother or sister of the scoping person's spouse." },
77
+ { code: 'NIECE', display: 'niece', definition: "The player of the role is a daughter of the scoping person's brother or sister or of the brother or sister of the scoping person's spouse." },
78
+ { code: 'UNCLE', display: 'uncle', definition: "The player of the role is a brother of the scoping person's mother or father." },
79
+ { code: 'MUNCLE', display: 'maternal uncle', definition: "The player of the role is a biological brother of the scoping person's biological mother." },
80
+ { code: 'PUNCLE', display: 'paternal uncle', definition: "The player of the role is a biological brother of the scoping person's biological father." },
81
+ { code: 'PRN', display: 'parent', definition: 'The player of the role is one who begets, gives birth to, or nurtures and raises the scoping entity.' },
82
+ { code: 'ADOPTP', display: 'adoptive parent', definition: 'The player of the role has taken the scoper into their family through legal means and raises them as their own child.' },
83
+ { code: 'ADOPTF', display: 'adoptive father', definition: 'The player of the role is a male who has taken the scoper into their family through legal means and raises them as his own child.' },
84
+ { code: 'ADOPTM', display: 'adoptive mother', definition: 'The player of the role is a female who has taken the scoper into their family through legal means and raises them as her own child.' },
85
+ { code: 'FTH', display: 'father', definition: 'The player of the role is a male who begets or raises or nurtures the scoping entity.' },
86
+ { code: 'FTHFOST', display: 'foster father', definition: 'The player of the role is a male state-certified caregiver responsible for the child placed in their care.' },
87
+ { code: 'NFTH', display: 'natural father', definition: 'The player of the role is a male who begets the scoping entity.' },
88
+ { code: 'NFTHF', display: 'natural father of fetus', definition: 'Indicates the biologic male parent of a fetus.' },
89
+ { code: 'STPFTH', display: 'stepfather', definition: "The player of the role is the husband of the scoping person's mother and not the scoping person's natural father." },
90
+ { code: 'MTH', display: 'mother', definition: 'The player of the role is a female who conceives, gives birth to, or raises and nurtures the scoping entity.' },
91
+ { code: 'GESTM', display: 'gestational mother', definition: 'The player is a female whose womb carries the fetus of the scoper.' },
92
+ { code: 'MTHFOST', display: 'foster mother', definition: 'The player of the role is a female state-certified caregiver responsible for the child placed in their care.' },
93
+ { code: 'NMTH', display: 'natural mother', definition: 'The player of the role is a female who conceives or gives birth to the scoping entity.' },
94
+ { code: 'NMTHF', display: 'natural mother of fetus', definition: 'The player is the biologic female parent of the scoping fetus.' },
95
+ { code: 'STPMTH', display: 'stepmother', definition: "The player of the role is the wife of the scoping person's father and not the scoping person's natural mother." },
96
+ { code: 'NPRN', display: 'natural parent', definition: 'The player of the role is a natural parent.' },
97
+ { code: 'PRNFOST', display: 'foster parent', definition: 'The player of the role is a state-certified caregiver responsible for the child placed in their care.' },
98
+ { code: 'STPPRN', display: 'step parent', definition: "The player of the role is the spouse of the scoping person's parent and not the scoping person's natural parent." },
99
+ { code: 'SIB', display: 'sibling', definition: 'The player of the role shares one or both parents in common with the scoping entity.' },
100
+ { code: 'BRO', display: 'brother', definition: 'The player of the role is a male sharing one or both parents in common with the scoping entity.' },
101
+ { code: 'HBRO', display: 'half-brother', definition: 'The player of the role is a male related to the scoping entity by sharing only one biological parent.' },
102
+ { code: 'NBRO', display: 'natural brother', definition: 'The player of the role is a male having the same biological parents as the scoping entity.' },
103
+ { code: 'TWINBRO', display: 'twin brother', definition: 'The scoper was carried in the same womb as the male player and shares common biological parents.' },
104
+ { code: 'FTWINBRO', display: 'fraternal twin brother', definition: 'The scoper was carried in the same womb as the male player and shares common biological parents but is the product of distinct egg/sperm pairs.' },
105
+ { code: 'ITWINBRO', display: 'identical twin brother', definition: 'The male scoper is an offspring of the same egg-sperm pair as the male player.' },
106
+ { code: 'STPBRO', display: 'stepbrother', definition: "The player of the role is a son of the scoping person's stepparent." },
107
+ { code: 'HSIB', display: 'half-sibling', definition: 'The player of the role is related to the scoping entity by sharing only one biological parent.' },
108
+ { code: 'HSIS', display: 'half-sister', definition: 'The player of the role is a female related to the scoping entity by sharing only one biological parent.' },
109
+ { code: 'NSIB', display: 'natural sibling', definition: 'The player of the role has both biological parents in common with the scoping entity.' },
110
+ { code: 'NSIS', display: 'natural sister', definition: 'The player of the role is a female having the same biological parents as the scoping entity.' },
111
+ { code: 'TWINSIS', display: 'twin sister', definition: 'The scoper was carried in the same womb as the female player and shares common biological parents.' },
112
+ { code: 'FTWINSIS', display: 'fraternal twin sister', definition: 'The scoper was carried in the same womb as the female player and shares common biological parents but is the product of distinct egg/sperm pairs.' },
113
+ { code: 'ITWINSIS', display: 'identical twin sister', definition: 'The female scoper is an offspring of the same egg-sperm pair as the female player.' },
114
+ { code: 'TWIN', display: 'twin', definition: 'The scoper and player were carried in the same womb and shared common biological parents.' },
115
+ { code: 'FTWIN', display: 'fraternal twin', definition: 'The scoper and player were carried in the same womb and share common biological parents but are the product of distinct egg/sperm pairs.' },
116
+ { code: 'ITWIN', display: 'identical twin', definition: 'The scoper and player are offspring of the same egg-sperm pair.' },
117
+ { code: 'SIS', display: 'sister', definition: 'The player of the role is a female sharing one or both parents in common with the scoping entity.' },
118
+ { code: 'STPSIS', display: 'stepsister', definition: "The player of the role is a daughter of the scoping person's stepparent." },
119
+ { code: 'STPSIB', display: 'step sibling', definition: "The player of the role is a child of the scoping person's stepparent." },
120
+ { code: 'SIGOTHR', display: 'significant other', definition: "A person who is important to one's well being; especially a spouse or one in a similar relationship." },
121
+ { code: 'DOMPART', display: 'domestic partner', definition: "The player of the role cohabits with the scoping person but is not the scoping person's spouse." },
122
+ { code: 'FMRSPS', display: 'former spouse', definition: 'Player of the role was previously joined to the scoping person in marriage and this marriage is now dissolved and inactive.' },
123
+ { code: 'SPS', display: 'spouse', definition: 'The player of the role is a marriage partner of the scoping person.' },
124
+ { code: 'HUSB', display: 'husband', definition: 'The player of the role is a man joined to a woman in marriage.' },
125
+ { code: 'WIFE', display: 'wife', definition: 'The player of the role is a woman joined to a man in marriage.' },
126
+ { code: 'FRND', display: 'unrelated friend', definition: 'The player of the role is a person who is known, liked, and trusted by the scoping person.' },
127
+ { code: 'NBOR', display: 'neighbor', definition: 'The player of the role lives near or next to the scoping person.' },
128
+ { code: 'ROOM', display: 'roommate', definition: 'One who shares living quarters with the subject.' },
129
+ ];
130
+ const PERSONAL_PREFERRED_ORDER = [
131
+ 'ONESELF', 'SPS', 'HUSB', 'WIFE', 'SIGOTHR', 'DOMPART', 'FMRSPS', 'ROOM',
132
+ 'CHILD', 'SON', 'DAU', 'SONC', 'DAUC', 'NCHILD',
133
+ 'CHLDADOPT', 'SONADOPT', 'DAUADOPT', 'CHLDFOST', 'SONFOST', 'DAUFOST',
134
+ 'STPCHLD', 'STPSON', 'STPDAU',
135
+ 'PRN', 'FTH', 'MTH', 'NFTH', 'NMTH',
136
+ 'ADOPTP', 'ADOPTF', 'ADOPTM', 'FTHFOST', 'MTHFOST', 'PRNFOST',
137
+ 'STPFTH', 'STPMTH', 'STPPRN', 'NPRN',
138
+ 'SIB', 'BRO', 'SIS', 'NBRO', 'NSIS', 'NSIB', 'HBRO', 'HSIS', 'HSIB',
139
+ 'TWIN', 'TWINBRO', 'TWINSIS', 'FTWIN', 'FTWINBRO', 'FTWINSIS',
140
+ 'ITWIN', 'ITWINBRO', 'ITWINSIS',
141
+ 'GRPRN', 'GRFTH', 'GRMTH', 'MGRPRN', 'PGRPRN', 'MGRFTH', 'PGRFTH', 'MGRMTH', 'PGRMTH',
142
+ 'GGRPRN', 'GGRFTH', 'GGRMTH', 'MGGRPRN', 'PGGRPRN', 'MGGRFTH', 'PGGRFTH', 'MGGRMTH', 'PGGRMTH',
143
+ 'GRNDCHILD', 'GRNDSON', 'GRNDDAU',
144
+ 'CHLDINLAW', 'SONINLAW', 'DAUINLAW', 'PRNINLAW', 'FTHINLAW', 'MTHINLAW',
145
+ 'SIBINLAW', 'BROINLAW', 'SISINLAW',
146
+ 'UNCLE', 'AUNT', 'MUNCLE', 'PAUNT',
147
+ 'NIENEPH', 'NEPHEW', 'NIECE',
148
+ 'COUSN', 'MCOUSN', 'PCOUSN',
149
+ 'FRND', 'NBOR',
150
+ ];
151
+ const _personalByCode = new Map(PERSONAL_RELATIONSHIP_LIST.map((r) => [r.code, r]));
152
+ const _personalPreferred = PERSONAL_PREFERRED_ORDER
153
+ .map((code) => _personalByCode.get(code))
154
+ .filter(Boolean);
155
+ const _personalRemaining = PERSONAL_RELATIONSHIP_LIST.filter((r) => !PERSONAL_PREFERRED_ORDER.includes(r.code));
156
+ /**
157
+ * Full ordered list of HL7 v3-PersonalRelationshipRoleType entries.
158
+ * Suitable for relationship pickers in health-sector family registration.
159
+ * Default role: `ONESELF` (patient represents themselves).
160
+ */
161
+ export const HL7_PERSONAL_RELATIONSHIP_ROLES = [
162
+ ..._personalPreferred,
163
+ ..._personalRemaining,
164
+ ];
165
+ // ---------------------------------------------------------------------------
166
+ // 2. v3-RoleCode — legal / functional representative subset
167
+ // ---------------------------------------------------------------------------
168
+ export const HL7_CODING_SYSTEM_V3_ROLE_CODE = 'http://terminology.hl7.org/CodeSystem/v3-RoleCode';
169
+ /**
170
+ * Legal representative / guardian roles from HL7 v3-RoleCode.
171
+ *
172
+ * Used when the owner of an individual record exercises a legal function
173
+ * rather than a personal relationship (e.g. animal-care sector, minors
174
+ * with court-appointed guardian, power of attorney).
175
+ *
176
+ * Default for animal-care sector: `RESPRSN` (Responsible party).
177
+ */
178
+ export const HL7_V3_ROLE_CODE_LEGAL_REPRESENTATIVE = [
179
+ {
180
+ code: 'RESPRSN',
181
+ display: 'Responsible party',
182
+ definition: 'The role played by a party who has legal responsibility for another party.',
183
+ },
184
+ {
185
+ code: 'GUARD',
186
+ display: 'Guardian',
187
+ definition: 'The role played by a person or institution legally empowered with responsibility for the care of a ward.',
188
+ },
189
+ {
190
+ code: 'GUADLTM',
191
+ display: 'Guardian ad lidem',
192
+ definition: 'The role played by a person appointed by the court to represent the best interests of a child or incompetent in a legal proceeding.',
193
+ },
194
+ {
195
+ code: 'POWATT',
196
+ display: 'Power of attorney',
197
+ definition: 'A relationship between two people in which one person acts on behalf of another in legal or financial matters.',
198
+ },
199
+ {
200
+ code: 'DPOWATT',
201
+ display: 'Durable power of attorney',
202
+ definition: 'A relationship between two people in which one person acts on behalf of another even if the grantor becomes incapacitated.',
203
+ },
204
+ ];
205
+ /** Default role code for animal-care and non-human subjects. */
206
+ export const HL7_DEFAULT_ROLE_ANIMAL_CARE = 'RESPRSN';
207
+ /** Default role code for health sector (patient self-represents). */
208
+ export const HL7_DEFAULT_ROLE_HEALTH = 'ONESELF';
@@ -1 +1,2 @@
1
1
  export * from './schemaorg';
2
+ export * from './hl7-roles';
@@ -1 +1,2 @@
1
1
  export * from './schemaorg.js';
2
+ export * from './hl7-roles.js';
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './AesManager';
2
2
  export * from './CryptographyService';
3
3
  export * from './hmac';
4
+ export * from './storage';
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './AesManager.js';
2
2
  export * from './CryptographyService.js';
3
3
  export * from './hmac.js';
4
+ export * from './storage/index.js';
@@ -0,0 +1,53 @@
1
+ import { RecordBase, VaultConfig } from '../models/resource-document';
2
+ export interface VaultQueryCondition {
3
+ attribute: string;
4
+ equals?: unknown;
5
+ in?: unknown[];
6
+ }
7
+ export interface VaultQuery {
8
+ where?: VaultQueryCondition[];
9
+ orderBy?: {
10
+ attribute: string;
11
+ direction: 'asc' | 'desc';
12
+ };
13
+ limit?: number;
14
+ offset?: number;
15
+ }
16
+ export declare abstract class IVaultRepository {
17
+ /** Writes one or more records into a collection. */
18
+ abstract put<T extends RecordBase>(collectionName: string, containers: T | T[]): Promise<boolean>;
19
+ /** Reads a single record by id. */
20
+ abstract get<T extends RecordBase>(collectionName: string, containerId: string): Promise<T | undefined>;
21
+ /** Queries records by structured conditions. */
22
+ abstract query<T extends RecordBase>(collectionName: string, query: VaultQuery): Promise<T[]>;
23
+ /** Marks a record as deleted. */
24
+ abstract delete(collectionName: string, containerId: string): Promise<boolean>;
25
+ }
26
+ export declare abstract class IServerVaultRepository extends IVaultRepository {
27
+ /** Creates a new physical vault/collection. */
28
+ abstract createNewVault(vaultConfig: VaultConfig): Promise<boolean>;
29
+ /** Checks if a tenant's logical registration record exists. */
30
+ abstract vaultExists(vaultId: string): Promise<boolean>;
31
+ /** Retrieves configuration for a specific vault. */
32
+ abstract getVaultConfig(vaultId: string): Promise<VaultConfig | undefined>;
33
+ /** Creates a new section within a vault. */
34
+ abstract createNewSection(collectionName: string, sectionId: string): Promise<boolean>;
35
+ /** Updates or creates a section with the provided records. */
36
+ abstract updateSection(collectionName: string, sectionId: string, containers?: RecordBase[]): Promise<boolean>;
37
+ /** Retrieves all section IDs from a vault. */
38
+ abstract getAllSections(collectionName: string): Promise<string[]>;
39
+ /** Checks if a section exists within a vault. */
40
+ abstract sectionExists(collectionName: string, sectionId: string): Promise<boolean>;
41
+ /** Retrieves a list of record identifiers from a section. */
42
+ abstract getContainersListInSection(collectionName: string, sectionId: string): Promise<string[]>;
43
+ /** Retrieves full records from a section. */
44
+ abstract getContainersInSection<T extends RecordBase>(collectionName: string, sectionId: string, excludeRecordTypes?: string[]): Promise<T[]>;
45
+ /** Section-aware put — sectionId optional for backwards compat. */
46
+ abstract put<T extends RecordBase>(collectionName: string, containers: T | T[], sectionId?: string): Promise<boolean>;
47
+ /** Section-aware get — sectionId optional. */
48
+ abstract get<T extends RecordBase>(collectionName: string, containerId: string, sectionId?: string): Promise<T | undefined>;
49
+ /** Retrieves all versions of a record by id. */
50
+ abstract getHistory(collectionName: string, containerId: string): Promise<RecordBase[]>;
51
+ /** Permanently removes records marked as deleted. */
52
+ abstract purge(collectionName: string): Promise<boolean>;
53
+ }
@@ -0,0 +1,25 @@
1
+ // Copyright 2025 Antifraud Services Inc. under the Apache License, Version 2.0.
2
+ // File: src/storage/IVaultRepository.ts
3
+ // ---------------------------------------------------------------------------
4
+ // Base contract — used by all channels (voice, chat, mobile)
5
+ //
6
+ // Each vault instance is scoped to a single actor/session context
7
+ // (e.g. callSid for voice, userId for text channels).
8
+ //
9
+ // collectionName → logical bucket within the vault (e.g. 'tokens', 'session')
10
+ // containerId → unique record id within the bucket
11
+ // ---------------------------------------------------------------------------
12
+ export class IVaultRepository {
13
+ }
14
+ // ---------------------------------------------------------------------------
15
+ // Server/multi-tenant extension — used by GW nodes (gdc-unid-node-ts, gwtemplate-node-ts)
16
+ //
17
+ // Adds multi-vault management, sections, history, and purge operations
18
+ // needed by server-side vault repositories (Firestore, Postgres, Mem-backend).
19
+ //
20
+ // TODO: migrate gdc-unid-node-ts and gwtemplate-node-ts vault.repository.ts
21
+ // to extend this interface once storage-sdk-firestore-ts and
22
+ // storage-sdk-postgres-ts are created as separate packages.
23
+ // ---------------------------------------------------------------------------
24
+ export class IServerVaultRepository extends IVaultRepository {
25
+ }
@@ -0,0 +1,30 @@
1
+ import { RecordBase } from '../models/resource-document';
2
+ import { IVaultRepository, VaultQuery } from './IVaultRepository';
3
+ /**
4
+ * In-memory implementation of IVaultRepository.
5
+ *
6
+ * Intended for:
7
+ * - Unit/integration tests across all packages
8
+ * - Short-lived runtime contexts (voice calls, transient sessions)
9
+ *
10
+ * Each instance is independent — instantiate one per actor/session context
11
+ * (e.g. one per CallSid in uhc-unid-chat-node) and discard on cleanup.
12
+ *
13
+ * TODO: For text channels with persistent sessions, use:
14
+ * - storage-sdk-firestore-ts → FirestoreVaultRepository (Google Cloud)
15
+ * - storage-sdk-postgres-ts → PostgresVaultRepository (Cloud SQL / self-hosted)
16
+ * - storage-sdk-sqlite-ts → SqliteVaultRepository (mobile / expo-sqlite)
17
+ * - storage-sdk-indexeddb-ts → IndexedDbVaultRepository (browser)
18
+ * - storage-sdk-py → Python equivalents
19
+ * All of the above will import IVaultRepository from gdc-common-utils-ts/storage.
20
+ */
21
+ export declare class VaultMemRepository extends IVaultRepository {
22
+ private readonly collections;
23
+ private ensureCollection;
24
+ /** Clears all state. Useful for test teardown or call-end cleanup. */
25
+ clear(): void;
26
+ put<T extends RecordBase>(collectionName: string, containers: T | T[]): Promise<boolean>;
27
+ get<T extends RecordBase>(collectionName: string, containerId: string): Promise<T | undefined>;
28
+ query<T extends RecordBase>(collectionName: string, query: VaultQuery): Promise<T[]>;
29
+ delete(collectionName: string, containerId: string): Promise<boolean>;
30
+ }
@@ -0,0 +1,78 @@
1
+ // Copyright 2025 Antifraud Services Inc. under the Apache License, Version 2.0.
2
+ // File: src/storage/VaultMemRepository.ts
3
+ import { IVaultRepository } from './IVaultRepository.js';
4
+ /**
5
+ * In-memory implementation of IVaultRepository.
6
+ *
7
+ * Intended for:
8
+ * - Unit/integration tests across all packages
9
+ * - Short-lived runtime contexts (voice calls, transient sessions)
10
+ *
11
+ * Each instance is independent — instantiate one per actor/session context
12
+ * (e.g. one per CallSid in uhc-unid-chat-node) and discard on cleanup.
13
+ *
14
+ * TODO: For text channels with persistent sessions, use:
15
+ * - storage-sdk-firestore-ts → FirestoreVaultRepository (Google Cloud)
16
+ * - storage-sdk-postgres-ts → PostgresVaultRepository (Cloud SQL / self-hosted)
17
+ * - storage-sdk-sqlite-ts → SqliteVaultRepository (mobile / expo-sqlite)
18
+ * - storage-sdk-indexeddb-ts → IndexedDbVaultRepository (browser)
19
+ * - storage-sdk-py → Python equivalents
20
+ * All of the above will import IVaultRepository from gdc-common-utils-ts/storage.
21
+ */
22
+ export class VaultMemRepository extends IVaultRepository {
23
+ collections = new Map();
24
+ ensureCollection(collectionName) {
25
+ if (!this.collections.has(collectionName)) {
26
+ this.collections.set(collectionName, new Map());
27
+ }
28
+ return this.collections.get(collectionName);
29
+ }
30
+ /** Clears all state. Useful for test teardown or call-end cleanup. */
31
+ clear() {
32
+ this.collections.clear();
33
+ }
34
+ async put(collectionName, containers) {
35
+ const col = this.ensureCollection(collectionName);
36
+ const items = Array.isArray(containers) ? containers : [containers];
37
+ for (const item of items) {
38
+ col.set(item.id, item);
39
+ }
40
+ return true;
41
+ }
42
+ async get(collectionName, containerId) {
43
+ return this.collections.get(collectionName)?.get(containerId);
44
+ }
45
+ async query(collectionName, query) {
46
+ const col = this.collections.get(collectionName);
47
+ if (!col)
48
+ return [];
49
+ let results = Array.from(col.values());
50
+ if (query.where?.length) {
51
+ results = results.filter((doc) => query.where.every((cond) => {
52
+ const val = doc[cond.attribute];
53
+ if (cond.equals !== undefined)
54
+ return val === cond.equals;
55
+ if (cond.in !== undefined)
56
+ return cond.in.includes(val);
57
+ return true;
58
+ }));
59
+ }
60
+ if (query.orderBy) {
61
+ const { attribute, direction } = query.orderBy;
62
+ results.sort((a, b) => {
63
+ const av = a[attribute];
64
+ const bv = b[attribute];
65
+ const cmp = av < bv ? -1 : av > bv ? 1 : 0;
66
+ return direction === 'asc' ? cmp : -cmp;
67
+ });
68
+ }
69
+ if (query.offset)
70
+ results = results.slice(query.offset);
71
+ if (query.limit)
72
+ results = results.slice(0, query.limit);
73
+ return results;
74
+ }
75
+ async delete(collectionName, containerId) {
76
+ return this.collections.get(collectionName)?.delete(containerId) ?? false;
77
+ }
78
+ }
@@ -0,0 +1,3 @@
1
+ export { IVaultRepository, IServerVaultRepository } from './IVaultRepository';
2
+ export type { VaultQuery, VaultQueryCondition } from './IVaultRepository';
3
+ export { VaultMemRepository } from './VaultMemRepository';
@@ -0,0 +1,4 @@
1
+ // Copyright 2025 Antifraud Services Inc. under the Apache License, Version 2.0.
2
+ // File: src/storage/index.ts
3
+ export { IVaultRepository, IServerVaultRepository } from './IVaultRepository.js';
4
+ export { VaultMemRepository } from './VaultMemRepository.js';
@@ -0,0 +1,51 @@
1
+ export type ConsentActorTargetInput = {
2
+ /** Canonical actor identifier (for example did:web:..., urn:taxid:..., urn:tel:..., email). */
3
+ identifier?: string;
4
+ /** Preferred URL/domain alias for organization actor resolution (maps to did:web:<host>). */
5
+ url?: string;
6
+ /** Legacy alias maintained for backwards compatibility. */
7
+ didWeb?: string;
8
+ /** Legacy alias maintained for backwards compatibility. */
9
+ organizationUrl?: string;
10
+ organizationTaxId?: string;
11
+ email?: string;
12
+ phone?: string;
13
+ };
14
+ export type SubjectIdentifierInput = {
15
+ subjectDid?: string;
16
+ subjectPhone?: string;
17
+ subjectGivenName?: string;
18
+ };
19
+ export type BuildConsentClaimsSimpleInput = SubjectIdentifierInput & {
20
+ actor: ConsentActorTargetInput;
21
+ actorRole: string;
22
+ purpose: string;
23
+ actions: string[];
24
+ consentIdentifier?: string;
25
+ consentDate?: string;
26
+ decision?: 'permit' | 'deny';
27
+ attachmentContentType?: string;
28
+ attachmentBase64?: string;
29
+ };
30
+ export type BuildConsentClaimsSimpleOptions = {
31
+ errorPrefix?: string;
32
+ consentIdentifierFactory?: () => string;
33
+ };
34
+ export type ConsentClaimsSimpleResult = {
35
+ actorIdentifier: string;
36
+ subjectIdentifier: string;
37
+ consentClaims: Record<string, unknown>;
38
+ };
39
+ export type ConsentClaimsWithCidResult = ConsentClaimsSimpleResult & {
40
+ claimsCid: string;
41
+ };
42
+ export declare function normalizePhone(value: string): string;
43
+ export declare function normalizeIdentifierToken(value: string): string;
44
+ export declare function resolveActorIdentifier(target: ConsentActorTargetInput, options?: {
45
+ errorPrefix?: string;
46
+ }): string;
47
+ export declare function resolveSubjectIdentifier(input: SubjectIdentifierInput, options?: {
48
+ errorPrefix?: string;
49
+ }): string;
50
+ export declare function buildConsentClaimsSimple(input: BuildConsentClaimsSimpleInput, options?: BuildConsentClaimsSimpleOptions): ConsentClaimsSimpleResult;
51
+ export declare function buildConsentClaimsSimpleWithCid(input: BuildConsentClaimsSimpleInput, options?: BuildConsentClaimsSimpleOptions): ConsentClaimsWithCidResult;
@@ -0,0 +1,90 @@
1
+ // Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
2
+ import { assignCidToClaimsId } from './fhir-cid.js';
3
+ export function normalizePhone(value) {
4
+ return String(value || '').replace(/[^\d+]/g, '');
5
+ }
6
+ export function normalizeIdentifierToken(value) {
7
+ return String(value || '')
8
+ .trim()
9
+ .toLowerCase()
10
+ .replace(/[^a-z0-9]+/g, '-')
11
+ .replace(/(^-|-$)/g, '');
12
+ }
13
+ function withPrefix(prefix, message) {
14
+ return prefix ? `${prefix} ${message}` : message;
15
+ }
16
+ export function resolveActorIdentifier(target, options = {}) {
17
+ const identifier = String(target?.identifier || '').trim();
18
+ if (identifier)
19
+ return identifier;
20
+ const didWeb = String(target?.didWeb || '').trim();
21
+ if (didWeb.startsWith('did:web:'))
22
+ return didWeb;
23
+ const orgUrl = String(target?.url || target?.organizationUrl || '').trim();
24
+ if (orgUrl) {
25
+ try {
26
+ const parsed = orgUrl.includes('://') ? new URL(orgUrl) : new URL(`https://${orgUrl}`);
27
+ if (parsed.hostname)
28
+ return `did:web:${parsed.hostname.toLowerCase()}`;
29
+ }
30
+ catch {
31
+ // Ignore malformed URL and continue with other fallbacks.
32
+ }
33
+ }
34
+ const email = String(target?.email || '').trim().toLowerCase();
35
+ if (email && email.includes('@'))
36
+ return email;
37
+ const taxId = String(target?.organizationTaxId || '').trim().toUpperCase();
38
+ if (taxId)
39
+ return `urn:taxid:${taxId}`;
40
+ const phone = normalizePhone(String(target?.phone || ''));
41
+ if (phone)
42
+ return `urn:tel:${phone}`;
43
+ throw new Error(withPrefix(options.errorPrefix, 'Could not resolve actor identifier from identifier/didWeb/url/email/taxId/phone.'));
44
+ }
45
+ export function resolveSubjectIdentifier(input, options = {}) {
46
+ const did = String(input?.subjectDid || '').trim();
47
+ if (did)
48
+ return did;
49
+ const phone = normalizePhone(String(input?.subjectPhone || ''));
50
+ const given = normalizeIdentifierToken(String(input?.subjectGivenName || ''));
51
+ if (phone && given)
52
+ return `urn:person:phone:${phone}:given:${given}`;
53
+ throw new Error(withPrefix(options.errorPrefix, 'grantProfessionalAccessSimple requires subjectDid or (subjectPhone + subjectGivenName).'));
54
+ }
55
+ export function buildConsentClaimsSimple(input, options = {}) {
56
+ const actorIdentifier = resolveActorIdentifier(input.actor || {}, { errorPrefix: options.errorPrefix });
57
+ const subjectIdentifier = resolveSubjectIdentifier(input, { errorPrefix: options.errorPrefix });
58
+ const consentDate = String(input.consentDate || '').trim() || new Date().toISOString().slice(0, 10);
59
+ const consentIdentifier = String(input.consentIdentifier || '').trim() || String(options.consentIdentifierFactory?.() || '').trim();
60
+ if (!consentIdentifier) {
61
+ throw new Error(withPrefix(options.errorPrefix, 'consentIdentifier is required when no consentIdentifierFactory is provided.'));
62
+ }
63
+ return {
64
+ actorIdentifier,
65
+ subjectIdentifier,
66
+ consentClaims: {
67
+ '@context': 'org.hl7.fhir.api',
68
+ 'Consent.decision': input.decision || 'permit',
69
+ 'Consent.subject': subjectIdentifier,
70
+ 'Consent.identifier': consentIdentifier,
71
+ 'Consent.date': consentDate,
72
+ 'Consent.purpose': input.purpose,
73
+ 'Consent.action': (input.actions || []).join(','),
74
+ 'Consent.actor-identifier': actorIdentifier,
75
+ 'Consent.actor-role': input.actorRole,
76
+ 'Consent.attachment-contentType': input.attachmentContentType || 'application/odrl+json',
77
+ 'Consent.attachment-data': input.attachmentBase64 || 'e30=',
78
+ },
79
+ };
80
+ }
81
+ export function buildConsentClaimsSimpleWithCid(input, options = {}) {
82
+ const built = buildConsentClaimsSimple(input, options);
83
+ const assigned = assignCidToClaimsId(built.consentClaims);
84
+ return {
85
+ actorIdentifier: built.actorIdentifier,
86
+ subjectIdentifier: built.subjectIdentifier,
87
+ consentClaims: assigned.claims,
88
+ claimsCid: assigned.cid,
89
+ };
90
+ }
@@ -0,0 +1,60 @@
1
+ export type FhirCanonicalizationOptions = {
2
+ /**
3
+ * Removes `meta.versionId` from canonical input to avoid self-referential hashes.
4
+ * Default: true.
5
+ */
6
+ stripMetaVersionId?: boolean;
7
+ /**
8
+ * Removes top-level narrative `text` if present.
9
+ * Default: false.
10
+ */
11
+ stripNarrativeText?: boolean;
12
+ /**
13
+ * Removes nested `id` fields in backbone elements (resource root `id` is preserved).
14
+ * Default: false.
15
+ */
16
+ stripNestedElementIds?: boolean;
17
+ };
18
+ export type FhirCidBuildOptions = {
19
+ canonicalization?: FhirCanonicalizationOptions;
20
+ /**
21
+ * CID multicodec for canonical FHIR JSON payloads.
22
+ * `0x0129` is DAG-JSON.
23
+ */
24
+ multicodecCode?: number;
25
+ };
26
+ export type FhirCidResult = {
27
+ cid: string;
28
+ versionId: string;
29
+ canonicalJson: string;
30
+ digestHex: string;
31
+ };
32
+ export type ClaimsCidResult = {
33
+ cid: string;
34
+ canonicalJson: string;
35
+ digestHex: string;
36
+ };
37
+ export type FhirCidVersionMapping = {
38
+ resourceType?: string;
39
+ resourceId?: string;
40
+ fullUrl?: string;
41
+ cid: string;
42
+ versionId: string;
43
+ };
44
+ export declare function canonicalizeFhirResource(resource: Record<string, unknown>, options?: FhirCanonicalizationOptions): string;
45
+ export declare function buildCidV1FromCanonicalJson(canonicalJson: string, multicodecCode?: number): FhirCidResult;
46
+ export declare function canonicalizeClaimsForCid(claims: Record<string, unknown>): string;
47
+ export declare function claimsToCid(claims: Record<string, unknown>): ClaimsCidResult;
48
+ export declare function assignCidToClaimsId(claims: Record<string, unknown>): {
49
+ claims: Record<string, unknown>;
50
+ cid: string;
51
+ };
52
+ export declare function fhirResourceToCid(resource: Record<string, unknown>, options?: FhirCidBuildOptions): FhirCidResult;
53
+ export declare function assignCidToFhirResourceVersionId(resource: Record<string, unknown>, options?: FhirCidBuildOptions): {
54
+ resource: Record<string, unknown>;
55
+ mapping: FhirCidVersionMapping;
56
+ };
57
+ export declare function assignCidToFhirBundleEntries(bundle: Record<string, unknown>, options?: FhirCidBuildOptions): {
58
+ bundle: Record<string, unknown>;
59
+ mappings: FhirCidVersionMapping[];
60
+ };
@@ -0,0 +1,152 @@
1
+ // Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
2
+ import { sha256 } from '@noble/hashes/sha2.js';
3
+ import { utf8ToBytes } from '@noble/hashes/utils.js';
4
+ import { encodeMultibase58btc } from './multibase58.js';
5
+ const DEFAULT_MULTICODEC_DAG_JSON = 0x0129;
6
+ const MULTIHASH_SHA2_256_CODE = 0x12;
7
+ const MULTIHASH_SHA2_256_LEN = 32;
8
+ const CID_V1 = 0x01;
9
+ function toHex(bytes) {
10
+ return Buffer.from(bytes).toString('hex');
11
+ }
12
+ function encodeVarint(value) {
13
+ if (!Number.isInteger(value) || value < 0) {
14
+ throw new Error(`Invalid varint value: ${value}`);
15
+ }
16
+ const out = [];
17
+ let n = value >>> 0;
18
+ while (n >= 0x80) {
19
+ out.push((n & 0x7f) | 0x80);
20
+ n >>>= 7;
21
+ }
22
+ out.push(n);
23
+ return Uint8Array.from(out);
24
+ }
25
+ function concatBytes(...parts) {
26
+ const total = parts.reduce((acc, part) => acc + part.length, 0);
27
+ const out = new Uint8Array(total);
28
+ let offset = 0;
29
+ for (const part of parts) {
30
+ out.set(part, offset);
31
+ offset += part.length;
32
+ }
33
+ return out;
34
+ }
35
+ function canonicalizeValue(value, options, depth) {
36
+ if (Array.isArray(value)) {
37
+ // FHIR array order can be significant; preserve order, canonicalize each element.
38
+ return value.map((entry) => canonicalizeValue(entry, options, depth + 1));
39
+ }
40
+ if (value && typeof value === 'object') {
41
+ const asRecord = value;
42
+ const keys = Object.keys(asRecord).sort();
43
+ const out = {};
44
+ for (const key of keys) {
45
+ if (options.stripNarrativeText && depth === 0 && key === 'text') {
46
+ continue;
47
+ }
48
+ if (options.stripNestedElementIds && depth > 0 && key === 'id') {
49
+ continue;
50
+ }
51
+ let next = asRecord[key];
52
+ if (next === undefined)
53
+ continue;
54
+ if (options.stripMetaVersionId && key === 'meta' && next && typeof next === 'object' && !Array.isArray(next)) {
55
+ const metaRecord = { ...next };
56
+ delete metaRecord.versionId;
57
+ next = metaRecord;
58
+ }
59
+ out[key] = canonicalizeValue(next, options, depth + 1);
60
+ }
61
+ return out;
62
+ }
63
+ return value;
64
+ }
65
+ export function canonicalizeFhirResource(resource, options = {}) {
66
+ const normalizedOptions = {
67
+ stripMetaVersionId: options.stripMetaVersionId ?? true,
68
+ stripNarrativeText: options.stripNarrativeText ?? false,
69
+ stripNestedElementIds: options.stripNestedElementIds ?? false,
70
+ };
71
+ const normalized = canonicalizeValue(resource, normalizedOptions, 0);
72
+ return JSON.stringify(normalized);
73
+ }
74
+ export function buildCidV1FromCanonicalJson(canonicalJson, multicodecCode = DEFAULT_MULTICODEC_DAG_JSON) {
75
+ const digest = sha256(utf8ToBytes(canonicalJson));
76
+ const multihash = concatBytes(Uint8Array.from([MULTIHASH_SHA2_256_CODE, MULTIHASH_SHA2_256_LEN]), digest);
77
+ const cidBytes = concatBytes(encodeVarint(CID_V1), encodeVarint(multicodecCode), multihash);
78
+ const cid = encodeMultibase58btc(cidBytes);
79
+ return {
80
+ cid,
81
+ versionId: cid,
82
+ canonicalJson,
83
+ digestHex: toHex(digest),
84
+ };
85
+ }
86
+ export function canonicalizeClaimsForCid(claims) {
87
+ const stripped = { ...(claims || {}) };
88
+ delete stripped['@context'];
89
+ delete stripped['@type'];
90
+ delete stripped['@id'];
91
+ const normalized = canonicalizeValue(stripped, {
92
+ stripMetaVersionId: false,
93
+ stripNarrativeText: false,
94
+ stripNestedElementIds: false,
95
+ }, 0);
96
+ return JSON.stringify(normalized);
97
+ }
98
+ export function claimsToCid(claims) {
99
+ const canonicalJson = canonicalizeClaimsForCid(claims);
100
+ const cidData = buildCidV1FromCanonicalJson(canonicalJson, DEFAULT_MULTICODEC_DAG_JSON);
101
+ return {
102
+ cid: cidData.cid,
103
+ canonicalJson,
104
+ digestHex: cidData.digestHex,
105
+ };
106
+ }
107
+ export function assignCidToClaimsId(claims) {
108
+ const out = JSON.parse(JSON.stringify(claims || {}));
109
+ const { cid } = claimsToCid(out);
110
+ out['@id'] = cid;
111
+ return {
112
+ claims: out,
113
+ cid,
114
+ };
115
+ }
116
+ export function fhirResourceToCid(resource, options = {}) {
117
+ const canonicalJson = canonicalizeFhirResource(resource, options.canonicalization);
118
+ return buildCidV1FromCanonicalJson(canonicalJson, options.multicodecCode ?? DEFAULT_MULTICODEC_DAG_JSON);
119
+ }
120
+ export function assignCidToFhirResourceVersionId(resource, options = {}) {
121
+ const cid = fhirResourceToCid(resource, options);
122
+ const out = JSON.parse(JSON.stringify(resource));
123
+ const meta = (out.meta && typeof out.meta === 'object' && !Array.isArray(out.meta))
124
+ ? { ...out.meta }
125
+ : {};
126
+ meta.versionId = cid.versionId;
127
+ out.meta = meta;
128
+ return {
129
+ resource: out,
130
+ mapping: {
131
+ resourceType: String(out.resourceType || ''),
132
+ resourceId: out.id ? String(out.id) : undefined,
133
+ cid: cid.cid,
134
+ versionId: cid.versionId,
135
+ },
136
+ };
137
+ }
138
+ export function assignCidToFhirBundleEntries(bundle, options = {}) {
139
+ const out = JSON.parse(JSON.stringify(bundle));
140
+ const entries = Array.isArray(out.entry) ? out.entry : [];
141
+ const mappings = [];
142
+ for (const entry of entries) {
143
+ const resource = entry?.resource;
144
+ if (!resource || typeof resource !== 'object' || Array.isArray(resource))
145
+ continue;
146
+ const assigned = assignCidToFhirResourceVersionId(resource, options);
147
+ entry.resource = assigned.resource;
148
+ assigned.mapping.fullUrl = entry.fullUrl ? String(entry.fullUrl) : undefined;
149
+ mappings.push(assigned.mapping);
150
+ }
151
+ return { bundle: out, mappings };
152
+ }
@@ -3,9 +3,11 @@ export * from './base-convert';
3
3
  export * from './baseN';
4
4
  export * from './bundle';
5
5
  export * from './content';
6
+ export * from './consent';
6
7
  export * from './did';
7
8
  export * from './didcomm';
8
9
  export * from './format-converter';
10
+ export * from './fhir-cid';
9
11
  export * from './jwt';
10
12
  export * from './manager-error';
11
13
  export * from './multibase58';
@@ -3,9 +3,11 @@ export * from './base-convert.js';
3
3
  export * from './baseN.js';
4
4
  export * from './bundle.js';
5
5
  export * from './content.js';
6
+ export * from './consent.js';
6
7
  export * from './did.js';
7
8
  export * from './didcomm.js';
8
9
  export * from './format-converter.js';
10
+ export * from './fhir-cid.js';
9
11
  export * from './jwt.js';
10
12
  export * from './manager-error.js';
11
13
  export * from './multibase58.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdc-common-utils-ts",
3
- "version": "1.2.0",
3
+ "version": "1.4.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -69,6 +69,18 @@
69
69
  "./interfaces": {
70
70
  "types": "./dist/interfaces/index.d.ts",
71
71
  "default": "./dist/interfaces/index.js"
72
+ },
73
+ "./storage": {
74
+ "types": "./dist/storage/index.d.ts",
75
+ "default": "./dist/storage/index.js"
76
+ },
77
+ "./storage/*": {
78
+ "types": "./dist/storage/*.d.ts",
79
+ "default": "./dist/storage/*.js"
80
+ },
81
+ "./adapters/node/crypto": {
82
+ "types": "./dist/adapters/node/crypto.d.ts",
83
+ "default": "./dist/adapters/node/crypto.js"
72
84
  }
73
85
  },
74
86
  "files": [