gdc-common-utils-ts 2.9.25 → 2.9.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -759,6 +759,18 @@ Example:
759
759
  import { ICryptography, MlkemPublicJwk } from 'gdc-common-utils-ts/interfaces/Cryptography.types';
760
760
  ```
761
761
 
762
+ ## Sector tenant identity
763
+
764
+ Use `buildLegalSectorOrganizationUrn(...)` to derive the stable public identity
765
+ of one legal organization inside one data-space sector. Use
766
+ `buildLegalSectorOrganizationAssetId(...)` for its opaque Fabric lookup key.
767
+ Changing the hosting provider or tenant DID does not change that key.
768
+
769
+ For tenant lifecycle calls, keep the neutral legal identifier in
770
+ `setIdentifierValue(...)` and select the exact hosted tenant with
771
+ `setTenantDid(...)`. Obtain that DID from the registered tenant/profile or
772
+ authority response; do not reconstruct it from display names.
773
+
762
774
  ## Auth-Flow Boundaries
763
775
 
764
776
  This package provides primitives, not orchestration.
@@ -69,6 +69,7 @@ export * from './individual-smart.js';
69
69
  export * from './individual-organization-claims.js';
70
70
  export * from './inter-tenant-access-contract.js';
71
71
  export * from './legal-organization-onboarding-editor.js';
72
+ export * from './legal-sector-organization-urn.js';
72
73
  export * from './organization-lifecycle.js';
73
74
  export * from './organization-employee-lifecycle.js';
74
75
  export * from './organization-did-binding.js';
@@ -69,6 +69,7 @@ export * from './individual-smart.js';
69
69
  export * from './individual-organization-claims.js';
70
70
  export * from './inter-tenant-access-contract.js';
71
71
  export * from './legal-organization-onboarding-editor.js';
72
+ export * from './legal-sector-organization-urn.js';
72
73
  export * from './organization-lifecycle.js';
73
74
  export * from './organization-employee-lifecycle.js';
74
75
  export * from './organization-did-binding.js';
@@ -0,0 +1,33 @@
1
+ export type LegalSectorOrganizationUrnInput = Readonly<{
2
+ /** Governed data-space sector, for example `health-care` or `animal-care`. */
3
+ sector: string;
4
+ /** ISO 3166-1 alpha-2 country code. */
5
+ country: string;
6
+ /** Optional ISO 3166-2 or governed first administrative subdivision. */
7
+ administrativeSublevel1?: string;
8
+ /** Optional second administrative subdivision. */
9
+ administrativeSublevel2?: string;
10
+ /** Optional third administrative subdivision. */
11
+ administrativeSublevel3?: string;
12
+ /** HL7 v2-0203-derived or governed extension code, such as TAX, EN or BN. */
13
+ identifierType: string;
14
+ /** Issuer-defined official identifier. Its casing is preserved. */
15
+ identifierValue: string;
16
+ }>;
17
+ /**
18
+ * Builds the organization-level public identifier from the governed legal URN
19
+ * grammar. All structural tokens are lower-cased; the official identifier is
20
+ * preserved exactly after trimming and NFKC normalization.
21
+ *
22
+ * Format:
23
+ * `urn:legal:<sector>:<country>:<admin1>:<admin2>:<admin3>:organization:<type>:<official-id>`
24
+ */
25
+ export declare function buildLegalSectorOrganizationUrn(input: LegalSectorOrganizationUrnInput): string;
26
+ /**
27
+ * Builds the stable Fabric lookup key for one organization-sector binding.
28
+ *
29
+ * The exact canonical legal-sector URN UTF-8 bytes are encoded as
30
+ * `urn:multibase:base58btc(multihash(SHA3-256))`. A provider/DID rotation does
31
+ * not change this key; only the binding asset state and history change.
32
+ */
33
+ export declare function buildLegalSectorOrganizationAssetId(organizationUrn: string): string;
@@ -0,0 +1,78 @@
1
+ // Copyright 2026 ConnectHealth.info (Connectin Solution & Applications Ltd.) under the Apache License, Version 2.0.
2
+ import { UrnPrefixes } from '../constants/urn.js';
3
+ import { encodeMultibaseSha3 } from './multibasehash.js';
4
+ const NORMALIZED_SEGMENT_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
5
+ function normalizeRequiredSegment(value, field) {
6
+ const normalized = String(value || '').trim().normalize('NFKC').toLowerCase();
7
+ if (!NORMALIZED_SEGMENT_PATTERN.test(normalized)) {
8
+ throw new Error(`Legal sector organization URN requires a valid ${field}.`);
9
+ }
10
+ return normalized;
11
+ }
12
+ function normalizeOptionalSegment(value, field) {
13
+ if (!String(value || '').trim())
14
+ return '';
15
+ return normalizeRequiredSegment(String(value), field);
16
+ }
17
+ /**
18
+ * Builds the organization-level public identifier from the governed legal URN
19
+ * grammar. All structural tokens are lower-cased; the official identifier is
20
+ * preserved exactly after trimming and NFKC normalization.
21
+ *
22
+ * Format:
23
+ * `urn:legal:<sector>:<country>:<admin1>:<admin2>:<admin3>:organization:<type>:<official-id>`
24
+ */
25
+ export function buildLegalSectorOrganizationUrn(input) {
26
+ const sector = normalizeRequiredSegment(input.sector, 'sector');
27
+ const country = normalizeRequiredSegment(input.country, 'country');
28
+ if (!/^[a-z]{2}$/.test(country)) {
29
+ throw new Error('Legal sector organization URN requires an ISO 3166-1 alpha-2 country.');
30
+ }
31
+ const administrativeSublevel1 = normalizeOptionalSegment(input.administrativeSublevel1, 'administrativeSublevel1');
32
+ const administrativeSublevel2 = normalizeOptionalSegment(input.administrativeSublevel2, 'administrativeSublevel2');
33
+ const administrativeSublevel3 = normalizeOptionalSegment(input.administrativeSublevel3, 'administrativeSublevel3');
34
+ const identifierType = normalizeRequiredSegment(input.identifierType, 'identifierType');
35
+ const identifierValue = String(input.identifierValue || '').trim().normalize('NFKC');
36
+ if (!identifierValue || /[:\s]/u.test(identifierValue)) {
37
+ throw new Error('Legal sector organization URN requires a colon-free identifierValue.');
38
+ }
39
+ return [
40
+ 'urn',
41
+ 'legal',
42
+ sector,
43
+ country,
44
+ administrativeSublevel1,
45
+ administrativeSublevel2,
46
+ administrativeSublevel3,
47
+ 'organization',
48
+ identifierType,
49
+ identifierValue,
50
+ ].join(':');
51
+ }
52
+ /**
53
+ * Builds the stable Fabric lookup key for one organization-sector binding.
54
+ *
55
+ * The exact canonical legal-sector URN UTF-8 bytes are encoded as
56
+ * `urn:multibase:base58btc(multihash(SHA3-256))`. A provider/DID rotation does
57
+ * not change this key; only the binding asset state and history change.
58
+ */
59
+ export function buildLegalSectorOrganizationAssetId(organizationUrn) {
60
+ const canonicalUrn = String(organizationUrn || '').trim().normalize('NFKC');
61
+ const parts = canonicalUrn.split(':');
62
+ if (parts.length !== 10 || parts[0] !== 'urn' || parts[1] !== 'legal' || parts[7] !== 'organization') {
63
+ throw new Error('Legal sector organization asset ID requires a canonical organization-level urn:legal identifier.');
64
+ }
65
+ const rebuilt = buildLegalSectorOrganizationUrn({
66
+ sector: parts[2],
67
+ country: parts[3],
68
+ administrativeSublevel1: parts[4],
69
+ administrativeSublevel2: parts[5],
70
+ administrativeSublevel3: parts[6],
71
+ identifierType: parts[8],
72
+ identifierValue: parts[9],
73
+ });
74
+ if (rebuilt !== canonicalUrn) {
75
+ throw new Error('Legal sector organization asset ID requires an already-canonical urn:legal identifier.');
76
+ }
77
+ return `${UrnPrefixes.Multibase}${encodeMultibaseSha3(canonicalUrn, 256)}`;
78
+ }
@@ -39,6 +39,8 @@ export declare class OrganizationLifecycleEditor {
39
39
  setIdentifierValue(identifierValue: string): this;
40
40
  /** Sets the jurisdiction-defined identifier type independently from its complete value. */
41
41
  setIdentifierType(identifierType: string): this;
42
+ /** Selects the exact hosted tenant DID when one legal organization has multiple sector tenants. */
43
+ setTenantDid(tenantDid: string): this;
42
44
  setTaxId(taxId: string): this;
43
45
  setOperation(operation: OrganizationLifecycleOperation): this;
44
46
  setRequestType(requestType: string): this;
@@ -48,6 +50,8 @@ export declare class OrganizationLifecycleEditor {
48
50
  getIdentifierValue(): string | undefined;
49
51
  /** Returns the jurisdiction-defined identifier type used by lifecycle authorization. */
50
52
  getIdentifierType(): string | undefined;
53
+ /** Returns the exact hosted tenant DID selected for this lifecycle operation. */
54
+ getTenantDid(): string | undefined;
51
55
  getTaxId(): string | undefined;
52
56
  getOperation(): OrganizationLifecycleOperation;
53
57
  getRequestType(): string | undefined;
@@ -83,6 +83,16 @@ export class OrganizationLifecycleEditor {
83
83
  });
84
84
  return this;
85
85
  }
86
+ /** Selects the exact hosted tenant DID when one legal organization has multiple sector tenants. */
87
+ setTenantDid(tenantDid) {
88
+ this.draft = patchDraft(this.draft, {
89
+ claims: {
90
+ ...this.draft.claims,
91
+ [ClaimsOrganizationSchemaorg.sameAs]: String(tenantDid).trim(),
92
+ },
93
+ });
94
+ return this;
95
+ }
86
96
  setTaxId(taxId) {
87
97
  this.draft = patchDraft(this.draft, {
88
98
  claims: {
@@ -117,6 +127,10 @@ export class OrganizationLifecycleEditor {
117
127
  getIdentifierType() {
118
128
  return normalizeText(this.draft.claims[ClaimsOrganizationSchemaorg.identifierType]) || undefined;
119
129
  }
130
+ /** Returns the exact hosted tenant DID selected for this lifecycle operation. */
131
+ getTenantDid() {
132
+ return normalizeText(this.draft.claims[ClaimsOrganizationSchemaorg.sameAs]) || undefined;
133
+ }
120
134
  getTaxId() {
121
135
  return normalizeText(this.draft.claims[ClaimsOrganizationSchemaorg.taxId]) || undefined;
122
136
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdc-common-utils-ts",
3
- "version": "2.9.25",
3
+ "version": "2.9.26",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },