gdc-common-utils-ts 2.3.0 → 2.3.2
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 +22 -0
- package/dist/CryptographyService.d.ts +3 -0
- package/dist/CryptographyService.js +64 -35
- package/dist/constants/identity-identifiers.d.ts +60 -7
- package/dist/constants/identity-identifiers.js +58 -7
- package/dist/constants/schemaorg.d.ts +4 -0
- package/dist/constants/schemaorg.js +4 -0
- package/dist/constants/urn.d.ts +1 -0
- package/dist/constants/urn.js +1 -0
- package/dist/convert/index.d.ts +1 -0
- package/dist/convert/index.js +1 -0
- package/dist/convert/schemaorg-to-gaia-x.d.ts +116 -0
- package/dist/convert/schemaorg-to-gaia-x.js +211 -0
- package/dist/examples/shared.d.ts +1 -1
- package/dist/examples/shared.js +1 -1
- package/dist/models/bundle-editor-types.d.ts +13 -3
- package/dist/models/bundle-editor-types.js +9 -1
- package/dist/models/gaia-x.d.ts +132 -0
- package/dist/models/gaia-x.js +26 -0
- package/dist/models/index.d.ts +2 -0
- package/dist/models/index.js +2 -0
- package/dist/models/interoperable-claims/invoice-claims.d.ts +1 -1
- package/dist/models/interoperable-claims/invoice-claims.js +2 -2
- package/dist/models/interoperable-claims/observation-claims.d.ts +2 -2
- package/dist/models/interoperable-claims/observation-claims.js +2 -2
- package/dist/models/jwe.d.ts +25 -0
- package/dist/models/subject-identifier-ledger.d.ts +16 -0
- package/dist/models/subject-identifier-ledger.js +1 -0
- package/dist/utils/bundle-editor-core.d.ts +9 -0
- package/dist/utils/bundle-editor-core.js +46 -0
- package/dist/utils/bundle-editor.d.ts +2 -0
- package/dist/utils/bundle-editor.js +2 -0
- package/dist/utils/bundle-entry-editor.d.ts +6 -0
- package/dist/utils/bundle-entry-editor.js +20 -0
- package/dist/utils/communication-consent-access-editor.d.ts +14 -1
- package/dist/utils/communication-consent-access-editor.js +27 -0
- package/dist/utils/consent-entry-editor.d.ts +42 -0
- package/dist/utils/consent-entry-editor.js +80 -0
- package/dist/utils/did.d.ts +2 -2
- package/dist/utils/did.js +3 -3
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/individual-identifier.d.ts +14 -0
- package/dist/utils/individual-identifier.js +39 -0
- package/dist/utils/multibasehash.d.ts +19 -5
- package/dist/utils/multibasehash.js +35 -10
- package/dist/utils/multiformat-profile.d.ts +4 -2
- package/dist/utils/multiformat-profile.js +5 -3
- package/dist/utils/related-person-entry-editor.d.ts +32 -0
- package/dist/utils/related-person-entry-editor.js +97 -0
- package/dist/utils/same-as.d.ts +10 -0
- package/dist/utils/same-as.js +28 -3
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -209,6 +209,11 @@ The `utils` export exposes reusable helpers for DID and message handling, such a
|
|
|
209
209
|
- `utils/content`
|
|
210
210
|
- `utils/normalize`
|
|
211
211
|
- `utils/unified-health-id` for provider-scoped Damm control digits over normalized provider + personal numeric sequences
|
|
212
|
+
- `utils/multibasehash` for `encodeMultibaseSha3(input, digestBits = 384)`,
|
|
213
|
+
returning a base58btc multibase-encoded SHA3 multihash
|
|
214
|
+
- `utils/multiformat-profile` for
|
|
215
|
+
`buildRawCidV1FromUtf8String(canonicalValue)`, returning
|
|
216
|
+
`CIDv1(raw, SHA3-384)` by default
|
|
212
217
|
- `utils/fhir-cid` for recursive FHIR canonicalization + CID generation + `meta.versionId` assignment
|
|
213
218
|
- `utils/fhir-validator` for adapter-based FHIR validation (`validateFhirResource`, pluggable formal validator)
|
|
214
219
|
- conversion, formatting, and multibase helpers
|
|
@@ -220,8 +225,25 @@ Example:
|
|
|
220
225
|
```ts
|
|
221
226
|
import { normalizeDidWeb, generateServiceId } from 'gdc-common-utils-ts/utils/did';
|
|
222
227
|
import { fhirResourceToCid, assignCidToFhirResourceVersionId } from 'gdc-common-utils-ts/utils/fhir-cid';
|
|
228
|
+
import { encodeMultibaseSha3 } from 'gdc-common-utils-ts/utils/multibasehash';
|
|
229
|
+
import { buildRawCidV1FromUtf8String } from 'gdc-common-utils-ts/utils/multiformat-profile';
|
|
230
|
+
|
|
231
|
+
const lookupMultihash = encodeMultibaseSha3('DL|US-CA|D1234567');
|
|
232
|
+
const blockchainAssetId = buildRawCidV1FromUtf8String('DL|US-CA|D1234567');
|
|
223
233
|
```
|
|
224
234
|
|
|
235
|
+
Individual lookup tokens keep the identifier type and jurisdiction separate:
|
|
236
|
+
`org.hl7.terminology.CodeSystem.v2-0203.NN|ES|12345678Z`. Import
|
|
237
|
+
`buildIndividualIdentifierLedgerAssetId(...)` when a GW must derive the opaque
|
|
238
|
+
SHA3-384 `urn:multibase` key used by the subject-identifier ledger. The raw
|
|
239
|
+
identifier must never be written to that ledger.
|
|
240
|
+
|
|
241
|
+
Both helpers hash the exact UTF-8 bytes supplied by the caller. Identifier,
|
|
242
|
+
FHIR-token or JSON canonicalization belongs to the contract that owns the
|
|
243
|
+
input. A multibase multihash is suitable as a deterministic lookup key; a CID
|
|
244
|
+
is suitable when the key must identify a content-addressed record or
|
|
245
|
+
blockchain asset.
|
|
246
|
+
|
|
225
247
|
### Convert
|
|
226
248
|
|
|
227
249
|
The `convert` export exposes resource-specific FHIR R4 conversion helpers such as:
|
|
@@ -49,6 +49,9 @@ export declare class CryptographyService implements ICryptography {
|
|
|
49
49
|
derivedCekBytes: Uint8Array;
|
|
50
50
|
}>;
|
|
51
51
|
decapsulate(encapsulatedBytes: Uint8Array, secretKeyBytes: Uint8Array): Promise<Uint8Array>;
|
|
52
|
+
private wrapCekForRecipient;
|
|
53
|
+
private unwrapRecipientCek;
|
|
54
|
+
private deriveRecipientKek;
|
|
52
55
|
signBytes(payloadBytes: Uint8Array, secretKeyBytes: Uint8Array, alg: MldsaAlg): Promise<Uint8Array>;
|
|
53
56
|
verifyBytes(signatureBytes: Uint8Array, dataBytes: Uint8Array, publicKey: PublicJwk): Promise<boolean>;
|
|
54
57
|
jwsToCompact(jws: DataCompactJWT): string;
|
|
@@ -4,6 +4,8 @@ import * as pako from 'pako';
|
|
|
4
4
|
import * as jwtUtils from './utils/jwt.js';
|
|
5
5
|
import { AesManager } from './AesManager.js';
|
|
6
6
|
import { Content } from './utils/content.js';
|
|
7
|
+
import { hkdf } from '@noble/hashes/hkdf.js';
|
|
8
|
+
import { sha256 } from '@noble/hashes/sha2.js';
|
|
7
9
|
/**
|
|
8
10
|
* Implements the ICryptography interface, providing a complete suite of low-level,
|
|
9
11
|
* stateless cryptographic functions. This service is the "engine" of the security layer,
|
|
@@ -113,23 +115,17 @@ export class CryptographyService {
|
|
|
113
115
|
}
|
|
114
116
|
// --- High-Level Workflows ---
|
|
115
117
|
async encryptJwe(payload, protectedHeader, secretJWKey, recipientsJWKeys) {
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
// A true multi-recipient JWE requires a single Content Encryption Key (CEK) that is then
|
|
119
|
-
// encrypted (wrapped) for each recipient. This code uses the KEM-derived shared secret as the CEK.
|
|
120
|
-
// This must be refactored to a key-wrapping approach to support multiple recipients correctly.
|
|
118
|
+
// v1 deliberately exposes one recipient while using a distinct random CEK.
|
|
119
|
+
// The recipient wrap is already compatible with a future General JWE profile.
|
|
121
120
|
if (recipientsJWKeys.length !== 1) {
|
|
122
121
|
// Temporarily throw until the architecture is fixed for multi-recipient.
|
|
123
122
|
throw new Error("CryptographyService.encryptJwe currently only supports a single recipient.");
|
|
124
123
|
}
|
|
125
124
|
const recipient = recipientsJWKeys[0];
|
|
126
125
|
const publicKeyBytes = Content.base64ToBytes(recipient.x);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
const { derivedCekBytes, // This is the actual Content Encryption Key
|
|
131
|
-
encapsulatedCekBytes // This is the encrypted key for the recipient
|
|
132
|
-
} = await this.encapsulate(cekSeedBytes, secretJWKey.dBytes, publicKeyBytes);
|
|
126
|
+
const cekBytes = await this.cryptoHelper.getRandomBytes(32);
|
|
127
|
+
const kemSeedBytes = await this.cryptoHelper.getRandomBytes(32);
|
|
128
|
+
const { derivedCekBytes: sharedSecret, encapsulatedCekBytes } = await this.encapsulate(kemSeedBytes, secretJWKey.dBytes, publicKeyBytes);
|
|
133
129
|
// 2. Now, use the *derived* CEK to encrypt the payload with AES.
|
|
134
130
|
const protectedHeaderB64Url = Content.objectToRawBase64UrlSafe(protectedHeader);
|
|
135
131
|
let payloadBytes = Content.objectToBytes(payload);
|
|
@@ -139,13 +135,13 @@ export class CryptographyService {
|
|
|
139
135
|
payloadString = Content.bytesToRawBase64UrlSafe(payloadBytes);
|
|
140
136
|
}
|
|
141
137
|
else {
|
|
142
|
-
payloadString = Content.
|
|
138
|
+
payloadString = Content.bytesToStringUTF8(payloadBytes);
|
|
143
139
|
}
|
|
144
|
-
const encrypted = await this.encrypt(payloadString,
|
|
145
|
-
|
|
140
|
+
const encrypted = await this.encrypt(payloadString, cekBytes, protectedHeaderB64Url);
|
|
141
|
+
const wrappedCek = await this.wrapCekForRecipient(cekBytes, sharedSecret, encapsulatedCekBytes, protectedHeaderB64Url, recipient.kid);
|
|
146
142
|
const recipientData = [{
|
|
147
|
-
header: { alg:
|
|
148
|
-
encrypted_key: Content.
|
|
143
|
+
header: { alg: 'ML-KEM-768+HKDF-SHA256+A256GCMKW', kid: recipient.kid },
|
|
144
|
+
encrypted_key: Content.objectToRawBase64UrlSafe(wrappedCek),
|
|
149
145
|
}];
|
|
150
146
|
return {
|
|
151
147
|
protected: protectedHeaderB64Url,
|
|
@@ -157,14 +153,16 @@ export class CryptographyService {
|
|
|
157
153
|
}
|
|
158
154
|
async encryptJweToCompact(payload, protectedHeader, secretJWKey, recipientJWKey) {
|
|
159
155
|
// 1. Construct the complete, final protected header by merging the main and recipient headers.
|
|
160
|
-
const recipientHeader = { alg:
|
|
156
|
+
const recipientHeader = { alg: 'ML-KEM-768+HKDF-SHA256+A256GCMKW', kid: recipientJWKey.kid };
|
|
161
157
|
const finalProtectedHeader = { ...protectedHeader, ...recipientHeader };
|
|
162
158
|
const protectedHeaderB64Url = Content.objectToRawBase64UrlSafe(finalProtectedHeader);
|
|
163
|
-
// 2.
|
|
159
|
+
// 2. Generate a fresh content key, then protect it for the ML-KEM recipient.
|
|
164
160
|
const publicKeyBytes = Content.base64ToBytes(recipientJWKey.x);
|
|
165
|
-
const
|
|
166
|
-
const
|
|
167
|
-
const
|
|
161
|
+
const cekBytes = await this.cryptoHelper.getRandomBytes(32);
|
|
162
|
+
const kemSeedBytes = await this.cryptoHelper.getRandomBytes(32);
|
|
163
|
+
const { derivedCekBytes: sharedSecret, encapsulatedCekBytes } = await this.encapsulate(kemSeedBytes, secretJWKey.dBytes, publicKeyBytes);
|
|
164
|
+
const wrappedCek = await this.wrapCekForRecipient(cekBytes, sharedSecret, encapsulatedCekBytes, protectedHeaderB64Url, recipientJWKey.kid);
|
|
165
|
+
const encryptedKeyB64Url = Content.objectToRawBase64UrlSafe(wrappedCek);
|
|
168
166
|
// 3. Encrypt the payload using the derived CEK and the *final* protected header as AAD.
|
|
169
167
|
const payloadBytes = typeof payload === 'string'
|
|
170
168
|
? Content.stringToBytesUTF8(payload)
|
|
@@ -173,13 +171,13 @@ export class CryptographyService {
|
|
|
173
171
|
// Note: Compressing a compact JWS string is often inefficient, but supported.
|
|
174
172
|
const compressedPayload = pako.deflate(payloadBytes);
|
|
175
173
|
const payloadString = Content.bytesToRawBase64UrlSafe(compressedPayload);
|
|
176
|
-
const encrypted = await this.encrypt(payloadString,
|
|
177
|
-
return `${protectedHeaderB64Url}.${
|
|
174
|
+
const encrypted = await this.encrypt(payloadString, cekBytes, protectedHeaderB64Url);
|
|
175
|
+
return `${protectedHeaderB64Url}.${encryptedKeyB64Url}.${encrypted.iv}.${encrypted.ciphertext}.${encrypted.tag}`;
|
|
178
176
|
}
|
|
179
|
-
const payloadString = Content.
|
|
180
|
-
const encrypted = await this.encrypt(payloadString,
|
|
177
|
+
const payloadString = Content.bytesToStringUTF8(payloadBytes);
|
|
178
|
+
const encrypted = await this.encrypt(payloadString, cekBytes, protectedHeaderB64Url);
|
|
181
179
|
// 4. Assemble the 5 parts of the compact JWE.
|
|
182
|
-
return `${protectedHeaderB64Url}.${
|
|
180
|
+
return `${protectedHeaderB64Url}.${encryptedKeyB64Url}.${encrypted.iv}.${encrypted.ciphertext}.${encrypted.tag}`;
|
|
183
181
|
}
|
|
184
182
|
async decryptJwe(jwe, secretKeyJwk) {
|
|
185
183
|
const jweObject = typeof jwe === 'string' ? this.parseCompactJwe(jwe) : jwe;
|
|
@@ -187,9 +185,7 @@ export class CryptographyService {
|
|
|
187
185
|
if (!recipient || !recipient.encrypted_key) {
|
|
188
186
|
throw new Error(`JWE does not contain a recipient with kid=${secretKeyJwk.kid}`);
|
|
189
187
|
}
|
|
190
|
-
|
|
191
|
-
const encapsulatedKeyBytes = Content.base64ToBytes(recipient.encrypted_key);
|
|
192
|
-
const cekBytes = await this.decapsulate(encapsulatedKeyBytes, secretKeyJwk.dBytes);
|
|
188
|
+
const cekBytes = await this.unwrapRecipientCek(recipient.encrypted_key, secretKeyJwk, jweObject.protected);
|
|
193
189
|
// Decrypt the payload
|
|
194
190
|
const encryptedData = { ciphertext: jweObject.ciphertext, iv: jweObject.iv, tag: jweObject.tag };
|
|
195
191
|
const decryptedPayloadString = await this.decrypt(encryptedData, cekBytes, jweObject.protected);
|
|
@@ -260,12 +256,9 @@ export class CryptographyService {
|
|
|
260
256
|
return this.aesManager.decrypt(encryptedData, cekBytes, aad);
|
|
261
257
|
}
|
|
262
258
|
async encapsulate(cekSeedBytes, secretKeyBytes, recipientPublicKeyBytes) {
|
|
263
|
-
//
|
|
264
|
-
//
|
|
265
|
-
//
|
|
266
|
-
// The `encapsulate` function from the noble library handles this correctly by accepting the
|
|
267
|
-
// seed as the second argument. It returns both the encapsulated key (`cipherText`)
|
|
268
|
-
// and the derived shared secret, which we must use as the actual AES key.
|
|
259
|
+
// FIPS 203 ML-KEM encapsulation returns a ciphertext and a 32-byte shared secret.
|
|
260
|
+
// `secretKeyBytes` is retained only for public API compatibility; encapsulation
|
|
261
|
+
// requires the recipient public key, not a sender private key.
|
|
269
262
|
const mlKem = await this.loadMlKem();
|
|
270
263
|
const { sharedSecret, cipherText } = await mlKem.ml_kem768.encapsulate(recipientPublicKeyBytes, cekSeedBytes);
|
|
271
264
|
return { derivedCekBytes: sharedSecret, encapsulatedCekBytes: cipherText };
|
|
@@ -274,6 +267,42 @@ export class CryptographyService {
|
|
|
274
267
|
const mlKem = await this.loadMlKem();
|
|
275
268
|
return mlKem.ml_kem768.decapsulate(encapsulatedBytes, secretKeyBytes);
|
|
276
269
|
}
|
|
270
|
+
async wrapCekForRecipient(cekBytes, sharedSecret, kemCiphertext, protectedHeader, recipientKid) {
|
|
271
|
+
const kek = this.deriveRecipientKek(sharedSecret, protectedHeader, recipientKid);
|
|
272
|
+
const wrapped = await this.encrypt(Content.bytesToRawBase64UrlSafe(cekBytes), kek, `${protectedHeader}.${recipientKid}.cek`);
|
|
273
|
+
return {
|
|
274
|
+
v: 'gdc-mlkem-cek-wrap-v1',
|
|
275
|
+
kem: 'ML-KEM-768',
|
|
276
|
+
kdf: 'HKDF-SHA-256',
|
|
277
|
+
wrap: 'A256GCM',
|
|
278
|
+
kemCiphertext: Content.bytesToRawBase64UrlSafe(kemCiphertext),
|
|
279
|
+
iv: wrapped.iv,
|
|
280
|
+
ciphertext: wrapped.ciphertext,
|
|
281
|
+
tag: wrapped.tag,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
async unwrapRecipientCek(encryptedKey, secretKeyJwk, protectedHeader) {
|
|
285
|
+
let wrapped;
|
|
286
|
+
try {
|
|
287
|
+
wrapped = Content.base64UrlSafeToJSON(encryptedKey);
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
// Legacy v0 used the raw ML-KEM ciphertext and the shared secret as CEK.
|
|
291
|
+
return this.decapsulate(Content.base64ToBytes(encryptedKey), secretKeyJwk.dBytes);
|
|
292
|
+
}
|
|
293
|
+
if (wrapped?.v !== 'gdc-mlkem-cek-wrap-v1' || wrapped.kem !== 'ML-KEM-768' || wrapped.kdf !== 'HKDF-SHA-256' || wrapped.wrap !== 'A256GCM') {
|
|
294
|
+
throw new Error('Unsupported ML-KEM CEK wrap profile.');
|
|
295
|
+
}
|
|
296
|
+
const sharedSecret = await this.decapsulate(Content.base64ToBytes(wrapped.kemCiphertext), secretKeyJwk.dBytes);
|
|
297
|
+
const kek = this.deriveRecipientKek(sharedSecret, protectedHeader, secretKeyJwk.kid);
|
|
298
|
+
const cek = Content.base64ToBytes(await this.decrypt({ iv: wrapped.iv, ciphertext: wrapped.ciphertext, tag: wrapped.tag }, kek, `${protectedHeader}.${secretKeyJwk.kid}.cek`));
|
|
299
|
+
if (cek.byteLength !== 32)
|
|
300
|
+
throw new Error('Invalid wrapped AES-256-GCM CEK.');
|
|
301
|
+
return cek;
|
|
302
|
+
}
|
|
303
|
+
deriveRecipientKek(sharedSecret, protectedHeader, recipientKid) {
|
|
304
|
+
return hkdf(sha256, sharedSecret, Content.stringToBytesUTF8('gdc-confidential-pqc-v1'), Content.stringToBytesUTF8(`${protectedHeader}.${recipientKid}.document-at-rest`), 32);
|
|
305
|
+
}
|
|
277
306
|
async signBytes(payloadBytes, secretKeyBytes, alg) {
|
|
278
307
|
const mlDsa = await this.loadMlDsa();
|
|
279
308
|
switch (alg) {
|
|
@@ -15,23 +15,76 @@
|
|
|
15
15
|
* Reference:
|
|
16
16
|
* http://terminology.hl7.org/CodeSystem/v2-0203
|
|
17
17
|
*/
|
|
18
|
+
export declare const HL7_V2_0203_IDENTIFIER_SYSTEM: "http://terminology.hl7.org/CodeSystem/v2-0203";
|
|
19
|
+
export declare const HL7_V2_0203_REVERSE_DNS_PREFIX: "org.hl7.terminology.CodeSystem.v2-0203";
|
|
20
|
+
export declare const HL7_V2_0203_IDENTIFIER_CODES: Readonly<{
|
|
21
|
+
readonly DriverLicense: "DL";
|
|
22
|
+
readonly CitizenshipCard: "CZ";
|
|
23
|
+
readonly NationalNumber: "NN";
|
|
24
|
+
readonly PassportNumber: "PPN";
|
|
25
|
+
readonly JurisdictionalHealthNumber: "JHN";
|
|
26
|
+
readonly WorkPermit: "WP";
|
|
27
|
+
readonly StudyPermit: "SP";
|
|
28
|
+
readonly HealthCard: "HC";
|
|
29
|
+
readonly DonorRecord: "DR";
|
|
30
|
+
readonly PatientIdentifier: "PI";
|
|
31
|
+
}>;
|
|
32
|
+
export type Hl7V20203IdentifierCode = typeof HL7_V2_0203_IDENTIFIER_CODES[keyof typeof HL7_V2_0203_IDENTIFIER_CODES];
|
|
33
|
+
/** Product-neutral document kinds used by subject identifier forms. */
|
|
34
|
+
export declare const INDIVIDUAL_IDENTIFIER_KINDS: Readonly<{
|
|
35
|
+
readonly NationalPerson: "national-person";
|
|
36
|
+
readonly Passport: "passport";
|
|
37
|
+
readonly HealthNumber: "health-number";
|
|
38
|
+
readonly DriverLicense: "driver-license";
|
|
39
|
+
readonly WorkPermit: "work-permit";
|
|
40
|
+
readonly StudyPermit: "study-permit";
|
|
41
|
+
}>;
|
|
42
|
+
export type IndividualIdentifierKind = typeof INDIVIDUAL_IDENTIFIER_KINDS[keyof typeof INDIVIDUAL_IDENTIFIER_KINDS];
|
|
43
|
+
export declare const INDIVIDUAL_IDENTIFIER_KIND_CODES: Readonly<{
|
|
44
|
+
readonly "national-person": "NN";
|
|
45
|
+
readonly passport: "PPN";
|
|
46
|
+
readonly "health-number": "JHN";
|
|
47
|
+
readonly "driver-license": "DL";
|
|
48
|
+
readonly "work-permit": "WP";
|
|
49
|
+
readonly "study-permit": "SP";
|
|
50
|
+
}>;
|
|
18
51
|
export declare enum IdKind {
|
|
19
52
|
/** ISO 18013-5 mobile driving licence credential. */
|
|
20
53
|
MobileDriverLicense = "org.iso.18013.5.1.mDL",
|
|
21
54
|
/** HL7 driver license identifier. */
|
|
22
|
-
PersonalDriverLicense = "org.hl7.terminology.
|
|
55
|
+
PersonalDriverLicense = "org.hl7.terminology.CodeSystem.v2-0203.DL",
|
|
23
56
|
/** HL7 citizenship card identifier. */
|
|
24
|
-
PersonalCitizenshipCard = "org.hl7.terminology.
|
|
57
|
+
PersonalCitizenshipCard = "org.hl7.terminology.CodeSystem.v2-0203.CZ",
|
|
25
58
|
/** HL7 national identity number. */
|
|
26
|
-
PersonalNationalNumber = "org.hl7.terminology.
|
|
59
|
+
PersonalNationalNumber = "org.hl7.terminology.CodeSystem.v2-0203.NN",
|
|
60
|
+
/** HL7 passport number. */
|
|
61
|
+
PersonalPassportNumber = "org.hl7.terminology.CodeSystem.v2-0203.PPN",
|
|
27
62
|
/** HL7 jurisdictional health number. */
|
|
28
|
-
|
|
63
|
+
RegionalHealthCardNumber = "org.hl7.terminology.CodeSystem.v2-0203.JHN",
|
|
64
|
+
/** @deprecated Use `RegionalHealthCardNumber`. */
|
|
65
|
+
RegionalHeathCardNumber = "org.hl7.terminology.CodeSystem.v2-0203.JHN",
|
|
66
|
+
/** HL7 work permit. */
|
|
67
|
+
PersonalWorkPermit = "org.hl7.terminology.CodeSystem.v2-0203.WP",
|
|
68
|
+
/** HL7 study permit. */
|
|
69
|
+
PersonalStudyPermit = "org.hl7.terminology.CodeSystem.v2-0203.SP",
|
|
29
70
|
/** HL7 local/private health card identifier. */
|
|
30
|
-
LocalHealthCard = "org.hl7.terminology.
|
|
71
|
+
LocalHealthCard = "org.hl7.terminology.CodeSystem.v2-0203.HC",
|
|
31
72
|
/** HL7 donor record identifier. */
|
|
32
|
-
LocalDonorRecord = "org.hl7.terminology.
|
|
73
|
+
LocalDonorRecord = "org.hl7.terminology.CodeSystem.v2-0203.DR",
|
|
33
74
|
/** HL7 local patient identifier. */
|
|
34
|
-
LocalPatientIdentifier = "org.hl7.terminology.
|
|
75
|
+
LocalPatientIdentifier = "org.hl7.terminology.CodeSystem.v2-0203.PI"
|
|
35
76
|
}
|
|
77
|
+
export declare const HL7_V2_0203_REVERSE_DNS_TYPES: Readonly<{
|
|
78
|
+
readonly DL: IdKind.PersonalDriverLicense;
|
|
79
|
+
readonly CZ: IdKind.PersonalCitizenshipCard;
|
|
80
|
+
readonly NN: IdKind.PersonalNationalNumber;
|
|
81
|
+
readonly PPN: IdKind.PersonalPassportNumber;
|
|
82
|
+
readonly JHN: IdKind.RegionalHealthCardNumber;
|
|
83
|
+
readonly WP: IdKind.PersonalWorkPermit;
|
|
84
|
+
readonly SP: IdKind.PersonalStudyPermit;
|
|
85
|
+
readonly HC: IdKind.LocalHealthCard;
|
|
86
|
+
readonly DR: IdKind.LocalDonorRecord;
|
|
87
|
+
readonly PI: IdKind.LocalPatientIdentifier;
|
|
88
|
+
}>;
|
|
36
89
|
/** Union helper for code that wants typed values without depending on the enum object. */
|
|
37
90
|
export type IdKindValue = typeof IdKind[keyof typeof IdKind];
|
|
@@ -15,22 +15,73 @@
|
|
|
15
15
|
* Reference:
|
|
16
16
|
* http://terminology.hl7.org/CodeSystem/v2-0203
|
|
17
17
|
*/
|
|
18
|
+
export const HL7_V2_0203_IDENTIFIER_SYSTEM = 'http://terminology.hl7.org/CodeSystem/v2-0203';
|
|
19
|
+
export const HL7_V2_0203_REVERSE_DNS_PREFIX = 'org.hl7.terminology.CodeSystem.v2-0203';
|
|
20
|
+
export const HL7_V2_0203_IDENTIFIER_CODES = Object.freeze({
|
|
21
|
+
DriverLicense: 'DL',
|
|
22
|
+
CitizenshipCard: 'CZ',
|
|
23
|
+
NationalNumber: 'NN',
|
|
24
|
+
PassportNumber: 'PPN',
|
|
25
|
+
JurisdictionalHealthNumber: 'JHN',
|
|
26
|
+
WorkPermit: 'WP',
|
|
27
|
+
StudyPermit: 'SP',
|
|
28
|
+
HealthCard: 'HC',
|
|
29
|
+
DonorRecord: 'DR',
|
|
30
|
+
PatientIdentifier: 'PI',
|
|
31
|
+
});
|
|
32
|
+
/** Product-neutral document kinds used by subject identifier forms. */
|
|
33
|
+
export const INDIVIDUAL_IDENTIFIER_KINDS = Object.freeze({
|
|
34
|
+
NationalPerson: 'national-person',
|
|
35
|
+
Passport: 'passport',
|
|
36
|
+
HealthNumber: 'health-number',
|
|
37
|
+
DriverLicense: 'driver-license',
|
|
38
|
+
WorkPermit: 'work-permit',
|
|
39
|
+
StudyPermit: 'study-permit',
|
|
40
|
+
});
|
|
41
|
+
export const INDIVIDUAL_IDENTIFIER_KIND_CODES = Object.freeze({
|
|
42
|
+
[INDIVIDUAL_IDENTIFIER_KINDS.NationalPerson]: HL7_V2_0203_IDENTIFIER_CODES.NationalNumber,
|
|
43
|
+
[INDIVIDUAL_IDENTIFIER_KINDS.Passport]: HL7_V2_0203_IDENTIFIER_CODES.PassportNumber,
|
|
44
|
+
[INDIVIDUAL_IDENTIFIER_KINDS.HealthNumber]: HL7_V2_0203_IDENTIFIER_CODES.JurisdictionalHealthNumber,
|
|
45
|
+
[INDIVIDUAL_IDENTIFIER_KINDS.DriverLicense]: HL7_V2_0203_IDENTIFIER_CODES.DriverLicense,
|
|
46
|
+
[INDIVIDUAL_IDENTIFIER_KINDS.WorkPermit]: HL7_V2_0203_IDENTIFIER_CODES.WorkPermit,
|
|
47
|
+
[INDIVIDUAL_IDENTIFIER_KINDS.StudyPermit]: HL7_V2_0203_IDENTIFIER_CODES.StudyPermit,
|
|
48
|
+
});
|
|
18
49
|
export var IdKind;
|
|
19
50
|
(function (IdKind) {
|
|
20
51
|
/** ISO 18013-5 mobile driving licence credential. */
|
|
21
52
|
IdKind["MobileDriverLicense"] = "org.iso.18013.5.1.mDL";
|
|
22
53
|
/** HL7 driver license identifier. */
|
|
23
|
-
IdKind["PersonalDriverLicense"] = "org.hl7.terminology.
|
|
54
|
+
IdKind["PersonalDriverLicense"] = "org.hl7.terminology.CodeSystem.v2-0203.DL";
|
|
24
55
|
/** HL7 citizenship card identifier. */
|
|
25
|
-
IdKind["PersonalCitizenshipCard"] = "org.hl7.terminology.
|
|
56
|
+
IdKind["PersonalCitizenshipCard"] = "org.hl7.terminology.CodeSystem.v2-0203.CZ";
|
|
26
57
|
/** HL7 national identity number. */
|
|
27
|
-
IdKind["PersonalNationalNumber"] = "org.hl7.terminology.
|
|
58
|
+
IdKind["PersonalNationalNumber"] = "org.hl7.terminology.CodeSystem.v2-0203.NN";
|
|
59
|
+
/** HL7 passport number. */
|
|
60
|
+
IdKind["PersonalPassportNumber"] = "org.hl7.terminology.CodeSystem.v2-0203.PPN";
|
|
28
61
|
/** HL7 jurisdictional health number. */
|
|
29
|
-
IdKind["
|
|
62
|
+
IdKind["RegionalHealthCardNumber"] = "org.hl7.terminology.CodeSystem.v2-0203.JHN";
|
|
63
|
+
/** @deprecated Use `RegionalHealthCardNumber`. */
|
|
64
|
+
IdKind["RegionalHeathCardNumber"] = "org.hl7.terminology.CodeSystem.v2-0203.JHN";
|
|
65
|
+
/** HL7 work permit. */
|
|
66
|
+
IdKind["PersonalWorkPermit"] = "org.hl7.terminology.CodeSystem.v2-0203.WP";
|
|
67
|
+
/** HL7 study permit. */
|
|
68
|
+
IdKind["PersonalStudyPermit"] = "org.hl7.terminology.CodeSystem.v2-0203.SP";
|
|
30
69
|
/** HL7 local/private health card identifier. */
|
|
31
|
-
IdKind["LocalHealthCard"] = "org.hl7.terminology.
|
|
70
|
+
IdKind["LocalHealthCard"] = "org.hl7.terminology.CodeSystem.v2-0203.HC";
|
|
32
71
|
/** HL7 donor record identifier. */
|
|
33
|
-
IdKind["LocalDonorRecord"] = "org.hl7.terminology.
|
|
72
|
+
IdKind["LocalDonorRecord"] = "org.hl7.terminology.CodeSystem.v2-0203.DR";
|
|
34
73
|
/** HL7 local patient identifier. */
|
|
35
|
-
IdKind["LocalPatientIdentifier"] = "org.hl7.terminology.
|
|
74
|
+
IdKind["LocalPatientIdentifier"] = "org.hl7.terminology.CodeSystem.v2-0203.PI";
|
|
36
75
|
})(IdKind || (IdKind = {}));
|
|
76
|
+
export const HL7_V2_0203_REVERSE_DNS_TYPES = Object.freeze({
|
|
77
|
+
[HL7_V2_0203_IDENTIFIER_CODES.DriverLicense]: IdKind.PersonalDriverLicense,
|
|
78
|
+
[HL7_V2_0203_IDENTIFIER_CODES.CitizenshipCard]: IdKind.PersonalCitizenshipCard,
|
|
79
|
+
[HL7_V2_0203_IDENTIFIER_CODES.NationalNumber]: IdKind.PersonalNationalNumber,
|
|
80
|
+
[HL7_V2_0203_IDENTIFIER_CODES.PassportNumber]: IdKind.PersonalPassportNumber,
|
|
81
|
+
[HL7_V2_0203_IDENTIFIER_CODES.JurisdictionalHealthNumber]: IdKind.RegionalHealthCardNumber,
|
|
82
|
+
[HL7_V2_0203_IDENTIFIER_CODES.WorkPermit]: IdKind.PersonalWorkPermit,
|
|
83
|
+
[HL7_V2_0203_IDENTIFIER_CODES.StudyPermit]: IdKind.PersonalStudyPermit,
|
|
84
|
+
[HL7_V2_0203_IDENTIFIER_CODES.HealthCard]: IdKind.LocalHealthCard,
|
|
85
|
+
[HL7_V2_0203_IDENTIFIER_CODES.DonorRecord]: IdKind.LocalDonorRecord,
|
|
86
|
+
[HL7_V2_0203_IDENTIFIER_CODES.PatientIdentifier]: IdKind.LocalPatientIdentifier,
|
|
87
|
+
});
|
|
@@ -3,7 +3,9 @@ export declare enum ClaimsServiceSchemaorg {
|
|
|
3
3
|
areaServed = "org.schema.Service.areaServed",
|
|
4
4
|
additionalType = "org.schema.Service.additionalType",
|
|
5
5
|
category = "org.schema.Service.category",
|
|
6
|
+
description = "org.schema.Service.description",
|
|
6
7
|
identifier = "org.schema.Service.identifier",
|
|
8
|
+
name = "org.schema.Service.name",
|
|
7
9
|
serviceType = "org.schema.Service.serviceType",
|
|
8
10
|
termsOfService = "org.schema.Service.termsOfService",
|
|
9
11
|
url = "org.schema.Service.url"
|
|
@@ -36,6 +38,8 @@ export declare enum ClaimsSoftwareApplicationSchemaorg {
|
|
|
36
38
|
* based on Schema.org vocabulary.
|
|
37
39
|
*/
|
|
38
40
|
export declare enum ClaimsOrganizationSchemaorg {
|
|
41
|
+
/** Public aliases used for exact organization or individual resolution. */
|
|
42
|
+
sameAs = "org.schema.Organization.sameAs",
|
|
39
43
|
/** ISO 3166-1 alpha-2 (two-letter country code). The jurisdiction could be the country or the region (county, province or state) */
|
|
40
44
|
addressCountry = "org.schema.Organization.address.addressCountry",
|
|
41
45
|
/** ISO 3166-2 code for administrative divisions. The jurisdiction could be the country or the region (county, province or state) */
|
|
@@ -5,7 +5,9 @@ export var ClaimsServiceSchemaorg;
|
|
|
5
5
|
ClaimsServiceSchemaorg["areaServed"] = "org.schema.Service.areaServed";
|
|
6
6
|
ClaimsServiceSchemaorg["additionalType"] = "org.schema.Service.additionalType";
|
|
7
7
|
ClaimsServiceSchemaorg["category"] = "org.schema.Service.category";
|
|
8
|
+
ClaimsServiceSchemaorg["description"] = "org.schema.Service.description";
|
|
8
9
|
ClaimsServiceSchemaorg["identifier"] = "org.schema.Service.identifier";
|
|
10
|
+
ClaimsServiceSchemaorg["name"] = "org.schema.Service.name";
|
|
9
11
|
ClaimsServiceSchemaorg["serviceType"] = "org.schema.Service.serviceType";
|
|
10
12
|
ClaimsServiceSchemaorg["termsOfService"] = "org.schema.Service.termsOfService";
|
|
11
13
|
ClaimsServiceSchemaorg["url"] = "org.schema.Service.url";
|
|
@@ -40,6 +42,8 @@ export var ClaimsSoftwareApplicationSchemaorg;
|
|
|
40
42
|
*/
|
|
41
43
|
export var ClaimsOrganizationSchemaorg;
|
|
42
44
|
(function (ClaimsOrganizationSchemaorg) {
|
|
45
|
+
/** Public aliases used for exact organization or individual resolution. */
|
|
46
|
+
ClaimsOrganizationSchemaorg["sameAs"] = "org.schema.Organization.sameAs";
|
|
43
47
|
/** ISO 3166-1 alpha-2 (two-letter country code). The jurisdiction could be the country or the region (county, province or state) */
|
|
44
48
|
ClaimsOrganizationSchemaorg["addressCountry"] = "org.schema.Organization.address.addressCountry";
|
|
45
49
|
/** ISO 3166-2 code for administrative divisions. The jurisdiction could be the country or the region (county, province or state) */
|
package/dist/constants/urn.d.ts
CHANGED
package/dist/constants/urn.js
CHANGED
package/dist/convert/index.d.ts
CHANGED
package/dist/convert/index.js
CHANGED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { ClaimsRecord } from '../models/resource-document';
|
|
2
|
+
import { type GaiaXCredentialDraft, type GaiaXLegalPersonCredentialSubject, type GaiaXServiceOfferingCredentialSubject, type GaiaXVcJwtAttachment, type IcaMemberDiscoveryData } from '../models/gaia-x';
|
|
3
|
+
import type { DidDocument } from '../models/did';
|
|
4
|
+
export interface SchemaOrgOrganizationRegistrationIdentifier {
|
|
5
|
+
additionalType: string;
|
|
6
|
+
value: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Reads the canonical schema.org `PropertyValue` organization identifier.
|
|
10
|
+
* During migration it also accepts the historical nested
|
|
11
|
+
* `identifier.identifier` form. When the structure is absent, `taxID` becomes
|
|
12
|
+
* a VAT/TAX fallback, matching ICA's OrganizationCredential issuance rule.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveSchemaOrgOrganizationRegistrationIdentifier(credentialSubject: Record<string, unknown>): SchemaOrgOrganizationRegistrationIdentifier;
|
|
15
|
+
/**
|
|
16
|
+
* Converts canonical schema.org organization claims into an unsigned Gaia-X
|
|
17
|
+
* ICAM 25.11 LegalPerson VC draft.
|
|
18
|
+
*
|
|
19
|
+
* Semantic boundary:
|
|
20
|
+
* - Gaia-X `LegalPerson` is the juridical organization/legal entity. It is not
|
|
21
|
+
* GDC's natural-person `LegalRepresentativeCredential`.
|
|
22
|
+
* - representative claims are intentionally never projected by this function.
|
|
23
|
+
* - VAT/tax remains in the source schema.org OrganizationCredential. Gaia-X's
|
|
24
|
+
* `gx:legalRegistrationNumber` is a resolvable reference to the separate
|
|
25
|
+
* registration/notary credential, not an assertion synthesized from VAT.
|
|
26
|
+
* - this function is deterministic and does not sign. The authoritative GW
|
|
27
|
+
* signs the returned draft as VC-JWT; ICA caches and verifies that exact JWT.
|
|
28
|
+
*
|
|
29
|
+
* This projection targets the credential structure and semantic model described
|
|
30
|
+
* by Gaia-X ICAM 25.11. Passing the resulting shape tests neither Gaia-X policy
|
|
31
|
+
* compliance nor GXDCH/TCK conformance.
|
|
32
|
+
*
|
|
33
|
+
* @see https://docs.gaia-x.eu/technical-committee/identity-credential-access-management/25.11/gaia-x_credentials/
|
|
34
|
+
* @see https://docs.gaia-x.eu/technical-committee/identity-credential-access-management/25.11/semantic_model/
|
|
35
|
+
*/
|
|
36
|
+
export declare function buildGaiaXLegalPersonCredentialDraft(input: Readonly<{
|
|
37
|
+
claims: ClaimsRecord;
|
|
38
|
+
credentialId: string;
|
|
39
|
+
subjectId: string;
|
|
40
|
+
issuerId: string;
|
|
41
|
+
legalRegistrationNumberCredentialId: string;
|
|
42
|
+
validFrom: string;
|
|
43
|
+
}>): GaiaXCredentialDraft<GaiaXLegalPersonCredentialSubject>;
|
|
44
|
+
/**
|
|
45
|
+
* Projects an ICA/GDC schema.org OrganizationCredential into a Gaia-X
|
|
46
|
+
* LegalPerson draft while preserving the organization `credentialSubject.id`.
|
|
47
|
+
*
|
|
48
|
+
* The source VC and Gaia-X VC are different signed statements, so their
|
|
49
|
+
* credential IDs must not silently collide. By default the Gaia-X credential
|
|
50
|
+
* receives `<source credential id>#gaia-x-legal-person`; callers may provide a
|
|
51
|
+
* separately resolvable ID. `registrationIdentifier` is returned for the
|
|
52
|
+
* notary/GXDCH registration step, while `gx:legalRegistrationNumber` remains a
|
|
53
|
+
* reference to the resulting registration credential.
|
|
54
|
+
*/
|
|
55
|
+
export declare function buildGaiaXLegalPersonProjectionFromOrganizationCredential(input: Readonly<{
|
|
56
|
+
organizationCredential: Record<string, unknown>;
|
|
57
|
+
credentialId?: string;
|
|
58
|
+
issuerId: string;
|
|
59
|
+
legalRegistrationNumberCredentialId: string;
|
|
60
|
+
addressSubdivisionCode?: string;
|
|
61
|
+
addressCountryCode?: string;
|
|
62
|
+
validFrom: string;
|
|
63
|
+
}>): Readonly<{
|
|
64
|
+
sourceCredentialId: string;
|
|
65
|
+
registrationIdentifier: SchemaOrgOrganizationRegistrationIdentifier;
|
|
66
|
+
credential: GaiaXCredentialDraft<GaiaXLegalPersonCredentialSubject>;
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* Converts schema.org service claims into an unsigned Gaia-X ServiceOffering
|
|
70
|
+
* VC draft. A service offering is independent from the participant credential:
|
|
71
|
+
* it references the LegalPerson credential through `gx:providedBy` and carries
|
|
72
|
+
* its own mandatory terms reference.
|
|
73
|
+
*
|
|
74
|
+
* The GW must sign this draft as a separate VC-JWT. A DCAT DataService is useful
|
|
75
|
+
* catalog metadata but is not a substitute for this credential.
|
|
76
|
+
*/
|
|
77
|
+
export declare function buildGaiaXServiceOfferingCredentialDraft(input: Readonly<{
|
|
78
|
+
claims: ClaimsRecord;
|
|
79
|
+
credentialId: string;
|
|
80
|
+
subjectId: string;
|
|
81
|
+
issuerId: string;
|
|
82
|
+
providedByCredentialId: string;
|
|
83
|
+
termsAndConditionsUrl: string;
|
|
84
|
+
termsAndConditionsHash: string;
|
|
85
|
+
validFrom: string;
|
|
86
|
+
}>): GaiaXCredentialDraft<GaiaXServiceOfferingCredentialSubject>;
|
|
87
|
+
/** Builds the mandatory first Gaia-X participant attachment for ICA discovery. */
|
|
88
|
+
export declare function buildGaiaXParticipantAttachment(input: Readonly<{
|
|
89
|
+
id: string;
|
|
90
|
+
jwt: string;
|
|
91
|
+
}>): GaiaXVcJwtAttachment;
|
|
92
|
+
/** Wraps an exact signed Gaia-X VC-JWT without decoding or re-signing it. */
|
|
93
|
+
export declare function buildGaiaXVcJwtAttachment(input: Readonly<{
|
|
94
|
+
id: string;
|
|
95
|
+
jwt: string;
|
|
96
|
+
role: GaiaXVcJwtAttachment['role'];
|
|
97
|
+
}>): GaiaXVcJwtAttachment;
|
|
98
|
+
/**
|
|
99
|
+
* Assembles one ICA member discovery entry and enforces the interoperable
|
|
100
|
+
* ordering contract: schema.org OrganizationCredential first in `vc[]`, and
|
|
101
|
+
* Gaia-X participant VC-JWT first in `attachments[]`.
|
|
102
|
+
*
|
|
103
|
+
* The caller owns signature verification and cache freshness. This helper does
|
|
104
|
+
* not derive or duplicate VAT outside `vc[]` and does not mutate signed data.
|
|
105
|
+
*/
|
|
106
|
+
export declare function buildIcaMemberDiscoveryData(input: Readonly<{
|
|
107
|
+
id: string;
|
|
108
|
+
vc: IcaMemberDiscoveryData['vc'];
|
|
109
|
+
did: {
|
|
110
|
+
document: DidDocument;
|
|
111
|
+
meta: IcaMemberDiscoveryData['did']['meta'];
|
|
112
|
+
};
|
|
113
|
+
attachments: GaiaXVcJwtAttachment[];
|
|
114
|
+
dcat?: IcaMemberDiscoveryData['dcat'];
|
|
115
|
+
meta?: IcaMemberDiscoveryData['meta'];
|
|
116
|
+
}>): IcaMemberDiscoveryData;
|