sos-data-utils-ts 0.2.1 → 0.2.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/CHANGELOG.md +9 -0
- package/README.md +13 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/subject-card-index.d.ts +41 -0
- package/dist/subject-card-index.js +69 -0
- package/package.json +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.2
|
|
4
|
+
|
|
5
|
+
- Add the product-neutral `speciesId7 + cardNumber20` preimage and lowercase
|
|
6
|
+
SHA3-256 asset-id builder shared by human and animal subject cards.
|
|
7
|
+
- Bind human cards implicitly to NCBI Taxonomy `9606` as `0009606`, without
|
|
8
|
+
displaying species or asking a person for it.
|
|
9
|
+
- Keep species outside every printed 21-digit card and exclude its final Damm
|
|
10
|
+
check digit from blockchain identity material.
|
|
11
|
+
|
|
3
12
|
## 0.2.1
|
|
4
13
|
|
|
5
14
|
- Add the shared product-neutral Task artifact schema backed by canonical flat
|
package/README.md
CHANGED
|
@@ -22,6 +22,19 @@ The shared Task authoring schema uses canonical flat FHIR-like claims from
|
|
|
22
22
|
correlation and output claims remain optional so the same contract supports
|
|
23
23
|
human work items and machine-created asynchronous jobs.
|
|
24
24
|
|
|
25
|
+
Subject-card index resolution uses one product-neutral 27-digit preimage:
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
speciesId7 + first20DigitsOfValidatedCardNumber21
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The final printed Damm digit is validation only and is excluded. Animal
|
|
32
|
+
products provide the animal's NCBI Taxonomy identifier separately from the
|
|
33
|
+
printed card. Human-health products use Homo sapiens (`9606`, projected as
|
|
34
|
+
`0009606`) implicitly and never display or request species. Only the lowercase
|
|
35
|
+
SHA3-256 digest of the 27 ASCII digits may cross the blockchain boundary; it
|
|
36
|
+
locates the active index provider and grants no data access.
|
|
37
|
+
|
|
25
38
|
The organization-verification contract resolves policy by business sector and
|
|
26
39
|
ISO country. The governed CA/US profiles are:
|
|
27
40
|
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export type SubjectSpeciesId7 = string;
|
|
2
|
+
export type SubjectCardNumber21 = string;
|
|
3
|
+
export type SubjectCardIndexCanonicalNumericId27 = string;
|
|
4
|
+
export type SubjectCardIndexAssetId = string;
|
|
5
|
+
/** Canonical NCBI Taxonomy identifier for Homo sapiens. */
|
|
6
|
+
export declare const HUMAN_NCBI_TAXONOMY_ID: "9606";
|
|
7
|
+
/** Seven-digit taxonomy projection used implicitly for human-card ledger keys. */
|
|
8
|
+
export declare const HUMAN_SPECIES_ID7: "0009606";
|
|
9
|
+
/**
|
|
10
|
+
* Projects a positive NCBI Taxonomy identifier to exactly seven decimal digits.
|
|
11
|
+
*
|
|
12
|
+
* This helper is product-neutral and therefore accepts Homo sapiens. A
|
|
13
|
+
* veterinary caller remains responsible for rejecting `9606` as an animal.
|
|
14
|
+
*/
|
|
15
|
+
export declare function normalizeSubjectSpeciesId7(ncbiTaxonomyId: string): SubjectSpeciesId7;
|
|
16
|
+
/**
|
|
17
|
+
* Builds the common 27-digit lookup preimage for a validated 21-digit card.
|
|
18
|
+
*
|
|
19
|
+
* The visible Damm digit is excluded because it detects transcription errors
|
|
20
|
+
* rather than contributing identity material. Species remains outside the
|
|
21
|
+
* printed number but prevents equal card payloads for different species from
|
|
22
|
+
* sharing one ledger key. Human callers pass `9606` (normally via the fixed
|
|
23
|
+
* `HUMAN_NCBI_TAXONOMY_ID` constant); they never ask a person for a species.
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildSubjectCardIndexCanonicalNumericId27(input: Readonly<{
|
|
26
|
+
ncbiTaxonomyId: string;
|
|
27
|
+
cardNumber21: string;
|
|
28
|
+
}>): SubjectCardIndexCanonicalNumericId27;
|
|
29
|
+
/**
|
|
30
|
+
* Returns lowercase hexadecimal SHA3-256 of the ASCII 27-digit preimage.
|
|
31
|
+
*
|
|
32
|
+
* Only this opaque digest crosses the blockchain boundary. The card number,
|
|
33
|
+
* taxonomy identifier and canonical preimage must not be written to the
|
|
34
|
+
* ledger. Resolving the digest locates an index provider; it grants no access.
|
|
35
|
+
*/
|
|
36
|
+
export declare function buildSubjectCardIndexAssetId(input: Readonly<{
|
|
37
|
+
ncbiTaxonomyId: string;
|
|
38
|
+
cardNumber21: string;
|
|
39
|
+
}>): Promise<SubjectCardIndexAssetId>;
|
|
40
|
+
/** Validates the exact lowercase SHA3-256 hexadecimal ledger-key profile. */
|
|
41
|
+
export declare function isSubjectCardIndexAssetId(value: string): value is SubjectCardIndexAssetId;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Copyright 2026 Connecting Solution & Applications Ltd under the Apache License, Version 2.0.
|
|
2
|
+
import { bytesToHexString } from 'gdc-common-utils-ts/utils/base-convert';
|
|
3
|
+
import { SHA3_256_MULTIHASH_PROFILE } from 'gdc-common-utils-ts/utils/multiformat-profile';
|
|
4
|
+
import { computeDammCheckDigit } from 'gdc-common-utils-ts/utils/unified-health-id';
|
|
5
|
+
/** Canonical NCBI Taxonomy identifier for Homo sapiens. */
|
|
6
|
+
export const HUMAN_NCBI_TAXONOMY_ID = '9606';
|
|
7
|
+
/** Seven-digit taxonomy projection used implicitly for human-card ledger keys. */
|
|
8
|
+
export const HUMAN_SPECIES_ID7 = '0009606';
|
|
9
|
+
/**
|
|
10
|
+
* Projects a positive NCBI Taxonomy identifier to exactly seven decimal digits.
|
|
11
|
+
*
|
|
12
|
+
* This helper is product-neutral and therefore accepts Homo sapiens. A
|
|
13
|
+
* veterinary caller remains responsible for rejecting `9606` as an animal.
|
|
14
|
+
*/
|
|
15
|
+
export function normalizeSubjectSpeciesId7(ncbiTaxonomyId) {
|
|
16
|
+
const source = String(ncbiTaxonomyId || '').trim();
|
|
17
|
+
if (!/^\d{1,7}$/.test(source)) {
|
|
18
|
+
throw new TypeError('NCBI Taxonomy identifier must contain at most seven digits.');
|
|
19
|
+
}
|
|
20
|
+
const normalized = source.replace(/^0+/, '') || '0';
|
|
21
|
+
if (normalized === '0') {
|
|
22
|
+
throw new TypeError('NCBI Taxonomy identifier must be positive.');
|
|
23
|
+
}
|
|
24
|
+
return normalized.padStart(7, '0');
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Builds the common 27-digit lookup preimage for a validated 21-digit card.
|
|
28
|
+
*
|
|
29
|
+
* The visible Damm digit is excluded because it detects transcription errors
|
|
30
|
+
* rather than contributing identity material. Species remains outside the
|
|
31
|
+
* printed number but prevents equal card payloads for different species from
|
|
32
|
+
* sharing one ledger key. Human callers pass `9606` (normally via the fixed
|
|
33
|
+
* `HUMAN_NCBI_TAXONOMY_ID` constant); they never ask a person for a species.
|
|
34
|
+
*/
|
|
35
|
+
export function buildSubjectCardIndexCanonicalNumericId27(input) {
|
|
36
|
+
const speciesId7 = normalizeSubjectSpeciesId7(input.ncbiTaxonomyId);
|
|
37
|
+
const cardNumber21 = normalizeCardNumber21(input.cardNumber21);
|
|
38
|
+
return `${speciesId7}${cardNumber21.slice(0, 20)}`;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Returns lowercase hexadecimal SHA3-256 of the ASCII 27-digit preimage.
|
|
42
|
+
*
|
|
43
|
+
* Only this opaque digest crosses the blockchain boundary. The card number,
|
|
44
|
+
* taxonomy identifier and canonical preimage must not be written to the
|
|
45
|
+
* ledger. Resolving the digest locates an index provider; it grants no access.
|
|
46
|
+
*/
|
|
47
|
+
export async function buildSubjectCardIndexAssetId(input) {
|
|
48
|
+
const canonicalNumericId27 = buildSubjectCardIndexCanonicalNumericId27(input);
|
|
49
|
+
const digest = SHA3_256_MULTIHASH_PROFILE.digest(new TextEncoder().encode(canonicalNumericId27));
|
|
50
|
+
return bytesToHexString(digest);
|
|
51
|
+
}
|
|
52
|
+
/** Validates the exact lowercase SHA3-256 hexadecimal ledger-key profile. */
|
|
53
|
+
export function isSubjectCardIndexAssetId(value) {
|
|
54
|
+
return /^[a-f0-9]{64}$/.test(String(value || ''));
|
|
55
|
+
}
|
|
56
|
+
function normalizeCardNumber21(value) {
|
|
57
|
+
const source = String(value || '').trim();
|
|
58
|
+
if (!source || !/^[0-9 -]+$/.test(source)) {
|
|
59
|
+
throw new TypeError('cardNumber21 must contain only decimal digits, spaces or hyphens.');
|
|
60
|
+
}
|
|
61
|
+
const digits = source.replace(/[ -]/g, '');
|
|
62
|
+
if (!/^\d{21}$/.test(digits)) {
|
|
63
|
+
throw new TypeError('cardNumber21 must contain exactly 21 digits.');
|
|
64
|
+
}
|
|
65
|
+
if (computeDammCheckDigit(digits.slice(0, 20)) !== digits.slice(20)) {
|
|
66
|
+
throw new TypeError('cardNumber21 has an invalid Damm check digit.');
|
|
67
|
+
}
|
|
68
|
+
return digits;
|
|
69
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sos-data-utils-ts",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Product-neutral SOS channel and BFF contract utilities",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
"./task-artifact-schema": {
|
|
23
23
|
"types": "./dist/task-artifact-schema.d.ts",
|
|
24
24
|
"default": "./dist/task-artifact-schema.js"
|
|
25
|
+
},
|
|
26
|
+
"./subject-card-index": {
|
|
27
|
+
"types": "./dist/subject-card-index.d.ts",
|
|
28
|
+
"default": "./dist/subject-card-index.js"
|
|
25
29
|
}
|
|
26
30
|
},
|
|
27
31
|
"files": [
|