gdc-common-utils-ts 2.5.13 → 2.5.15
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/dist/examples/organization-role-license.d.ts +2 -6
- package/dist/examples/organization-role-license.js +6 -15
- package/dist/models/organization-role-license.d.ts +7 -19
- package/dist/utils/organization-role-license.d.ts +4 -19
- package/dist/utils/organization-role-license.js +22 -36
- package/package.json +1 -1
|
@@ -2,12 +2,8 @@ import type { OrganizationRoleLicense } from '../models/organization-role-licens
|
|
|
2
2
|
import { type OrganizationRoleLicenseIdentity } from '../utils/organization-role-license';
|
|
3
3
|
/** Reusable synthetic identity for role-licence contract and consumer tests. */
|
|
4
4
|
export declare const EXAMPLE_ORGANIZATION_ROLE_LICENSE_IDENTITY: OrganizationRoleLicenseIdentity;
|
|
5
|
-
/** Reusable
|
|
6
|
-
export declare const EXAMPLE_ORGANIZATION_ROLE_LICENSE_POLICIES: readonly (Readonly<{
|
|
7
|
-
sector: "";
|
|
8
|
-
active: true;
|
|
9
|
-
maxDevices: null;
|
|
10
|
-
}> | Readonly<{
|
|
5
|
+
/** Reusable exact-sector policies; no empty-sector wildcard is authored. */
|
|
6
|
+
export declare const EXAMPLE_ORGANIZATION_ROLE_LICENSE_POLICIES: readonly (import("..").OrganizationRoleLicenseSectorPolicy | Readonly<{
|
|
11
7
|
sector: "animal-care";
|
|
12
8
|
active: false;
|
|
13
9
|
maxDevices: 2;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
2
|
import { buildStableActorIdentifier, StableActorContactKinds } from '../utils/actor-identifier.js';
|
|
3
|
-
import { buildOrganizationRoleLicenseId, } from '../utils/organization-role-license.js';
|
|
4
|
-
import { EXAMPLE_EMAIL_PROFESSIONAL,
|
|
3
|
+
import { buildOrganizationRoleLicenseId, DEFAULT_ORGANIZATION_ROLE_LICENSE_POLICY, } from '../utils/organization-role-license.js';
|
|
4
|
+
import { EXAMPLE_EMAIL_PROFESSIONAL, EXAMPLE_JURISDICTION, EXAMPLE_LEGAL_ORGANIZATION_TAX_ID, EXAMPLE_ORGANIZATION_CONTROLLER_ROLE, } from './shared.js';
|
|
5
|
+
import { DataspaceSectors } from '../constants/sectors.js';
|
|
5
6
|
/** Reusable synthetic identity for role-licence contract and consumer tests. */
|
|
6
7
|
export const EXAMPLE_ORGANIZATION_ROLE_LICENSE_IDENTITY = Object.freeze({
|
|
7
8
|
jurisdiction: EXAMPLE_JURISDICTION,
|
|
@@ -12,10 +13,10 @@ export const EXAMPLE_ORGANIZATION_ROLE_LICENSE_IDENTITY = Object.freeze({
|
|
|
12
13
|
}),
|
|
13
14
|
licensedRole: EXAMPLE_ORGANIZATION_CONTROLLER_ROLE,
|
|
14
15
|
});
|
|
15
|
-
/** Reusable
|
|
16
|
+
/** Reusable exact-sector policies; no empty-sector wildcard is authored. */
|
|
16
17
|
export const EXAMPLE_ORGANIZATION_ROLE_LICENSE_POLICIES = Object.freeze([
|
|
17
|
-
|
|
18
|
-
Object.freeze({ sector:
|
|
18
|
+
DEFAULT_ORGANIZATION_ROLE_LICENSE_POLICY,
|
|
19
|
+
Object.freeze({ sector: DataspaceSectors.AnimalCare, active: false, maxDevices: 2 }),
|
|
19
20
|
]);
|
|
20
21
|
/** Public ledger fixture: no clear contact or tenant-local employee UUID. */
|
|
21
22
|
export const EXAMPLE_ORGANIZATION_ROLE_LICENSE = Object.freeze({
|
|
@@ -23,16 +24,6 @@ export const EXAMPLE_ORGANIZATION_ROLE_LICENSE = Object.freeze({
|
|
|
23
24
|
...EXAMPLE_ORGANIZATION_ROLE_LICENSE_IDENTITY,
|
|
24
25
|
status: 'active',
|
|
25
26
|
data: [...EXAMPLE_ORGANIZATION_ROLE_LICENSE_POLICIES],
|
|
26
|
-
devices: [
|
|
27
|
-
Object.freeze({
|
|
28
|
-
clientId: EXAMPLE_EMPLOYEE_DEVICE_CLIENT_ID_PRIMARY,
|
|
29
|
-
clientInstanceId: EXAMPLE_EMPLOYEE_DEVICE_INSTANCE_ID_PRIMARY,
|
|
30
|
-
sector: EXAMPLE_SECTOR,
|
|
31
|
-
host: `https://${EXAMPLE_HOST_PUBLIC_HOSTNAME}`,
|
|
32
|
-
status: 'active',
|
|
33
|
-
activatedAt: 1_700_000_000,
|
|
34
|
-
}),
|
|
35
|
-
],
|
|
36
27
|
createdAt: 1_700_000_000,
|
|
37
28
|
updatedAt: 1_700_000_000,
|
|
38
29
|
});
|
|
@@ -1,34 +1,23 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DataspaceSector } from '../constants/sectors';
|
|
2
2
|
/** Lifecycle of one organization-owned, role-bearing licence assignment. */
|
|
3
3
|
export type OrganizationRoleLicenseStatus = 'active' | 'revoked';
|
|
4
4
|
/**
|
|
5
5
|
* Contractual policy for one sector.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* does not mean an unlimited number of installations.
|
|
7
|
+
* Every entry targets one canonical dataspace sector. Omitting `maxDevices`
|
|
8
|
+
* delegates the numeric limit to the GW/portal policy.
|
|
10
9
|
*/
|
|
11
10
|
export interface OrganizationRoleLicenseSectorPolicy {
|
|
12
|
-
sector:
|
|
11
|
+
sector: DataspaceSector;
|
|
13
12
|
active: boolean;
|
|
14
|
-
maxDevices
|
|
15
|
-
}
|
|
16
|
-
/** One concrete DCR installation registered against the licence. */
|
|
17
|
-
export interface OrganizationRoleLicenseDevice {
|
|
18
|
-
clientId: string;
|
|
19
|
-
clientInstanceId: string;
|
|
20
|
-
sector: string;
|
|
21
|
-
host: string;
|
|
22
|
-
status: DeviceBindingStatus;
|
|
23
|
-
activatedAt: number;
|
|
24
|
-
revokedAt?: number;
|
|
13
|
+
maxDevices?: number;
|
|
25
14
|
}
|
|
26
15
|
/**
|
|
27
16
|
* Public ledger projection of one licence assigned by an organization.
|
|
28
17
|
*
|
|
29
18
|
* The stable contact is a one-way `urn:multibase:` identifier. Clear email,
|
|
30
|
-
* telephone, tenant-local employee UUIDs, payment details
|
|
31
|
-
* permissions must never be written to this asset.
|
|
19
|
+
* telephone, tenant-local employee UUIDs, payment details, DCR registrations,
|
|
20
|
+
* hosts and application permissions must never be written to this asset.
|
|
32
21
|
*/
|
|
33
22
|
export interface OrganizationRoleLicense {
|
|
34
23
|
id: string;
|
|
@@ -39,7 +28,6 @@ export interface OrganizationRoleLicense {
|
|
|
39
28
|
licensedRole: string;
|
|
40
29
|
status: OrganizationRoleLicenseStatus;
|
|
41
30
|
data: OrganizationRoleLicenseSectorPolicy[];
|
|
42
|
-
devices: OrganizationRoleLicenseDevice[];
|
|
43
31
|
createdAt: number;
|
|
44
32
|
updatedAt: number;
|
|
45
33
|
revokedAt?: number;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import type { OrganizationRoleLicense,
|
|
1
|
+
import type { OrganizationRoleLicense, OrganizationRoleLicenseSectorPolicy } from '../models/organization-role-license';
|
|
2
2
|
export type OrganizationRoleLicenseIdentity = Readonly<{
|
|
3
3
|
jurisdiction: string;
|
|
4
4
|
organizationOfficialId: string;
|
|
5
5
|
stableContactIdentifier: string;
|
|
6
6
|
licensedRole: string;
|
|
7
7
|
}>;
|
|
8
|
+
export declare const DEFAULT_ORGANIZATION_ROLE_LICENSE_POLICY: OrganizationRoleLicenseSectorPolicy;
|
|
8
9
|
export declare function validateOrganizationOfficialId(value: string): string;
|
|
9
10
|
/**
|
|
10
11
|
* Builds the exact, compact licence preimage agreed across portals and hosts.
|
|
@@ -15,28 +16,12 @@ export declare function buildOrganizationRoleLicensePreimage(identity: Organizat
|
|
|
15
16
|
export declare function buildOrganizationRoleLicenseId(identity: OrganizationRoleLicenseIdentity): string;
|
|
16
17
|
/** Validates and de-duplicates sector policies while preserving input order. */
|
|
17
18
|
export declare function normalizeOrganizationRoleLicensePolicies(policies: readonly OrganizationRoleLicenseSectorPolicy[]): OrganizationRoleLicenseSectorPolicy[];
|
|
18
|
-
/**
|
|
19
|
+
/** Resolves the exact canonical sector policy. */
|
|
19
20
|
export declare function resolveOrganizationRoleLicensePolicy(policies: readonly OrganizationRoleLicenseSectorPolicy[], sector: string): OrganizationRoleLicenseSectorPolicy | undefined;
|
|
20
21
|
/** Returns the contractual limit or the positive GW/portal default. */
|
|
21
22
|
export declare function resolveOrganizationRoleLicenseMaxDevices(policy: OrganizationRoleLicenseSectorPolicy, defaultMaxDevices: number): number;
|
|
22
|
-
/** Checks global status plus the resolved exact
|
|
23
|
+
/** Checks global status plus the resolved exact-sector policy. */
|
|
23
24
|
export declare function organizationRoleLicenseAllowsSector(license: Readonly<{
|
|
24
25
|
status: OrganizationRoleLicense['status'];
|
|
25
26
|
data: readonly OrganizationRoleLicenseSectorPolicy[];
|
|
26
27
|
}>, sector: string): boolean;
|
|
27
|
-
/** Active DCR installations are counted per concrete sector, across hosts/apps. */
|
|
28
|
-
export declare function countActiveOrganizationRoleLicenseDevices(devices: readonly OrganizationRoleLicenseDevice[], sector: string): number;
|
|
29
|
-
/**
|
|
30
|
-
* Deterministic DCR admission decision. Re-registering the same active client
|
|
31
|
-
* is idempotent and does not consume an additional device slot.
|
|
32
|
-
*/
|
|
33
|
-
export declare function organizationRoleLicenseAllowsDevice(license: Readonly<{
|
|
34
|
-
status: OrganizationRoleLicense['status'];
|
|
35
|
-
data: readonly OrganizationRoleLicenseSectorPolicy[];
|
|
36
|
-
devices: readonly OrganizationRoleLicenseDevice[];
|
|
37
|
-
}>, input: Readonly<{
|
|
38
|
-
sector: string;
|
|
39
|
-
clientId: string;
|
|
40
|
-
clientInstanceId: string;
|
|
41
|
-
defaultMaxDevices: number;
|
|
42
|
-
}>): boolean;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
2
|
import { encodeMultibaseSha3 } from './multibasehash.js';
|
|
3
|
+
import { DataspaceSectors } from '../constants/sectors.js';
|
|
3
4
|
function required(value, label) {
|
|
4
5
|
const normalized = String(value || '').trim();
|
|
5
6
|
if (!normalized)
|
|
@@ -9,6 +10,10 @@ function required(value, label) {
|
|
|
9
10
|
function normalizedSector(value) {
|
|
10
11
|
return String(value || '').trim().toLowerCase();
|
|
11
12
|
}
|
|
13
|
+
export const DEFAULT_ORGANIZATION_ROLE_LICENSE_POLICY = Object.freeze({
|
|
14
|
+
sector: DataspaceSectors.OneHealthResearch,
|
|
15
|
+
active: true,
|
|
16
|
+
});
|
|
12
17
|
function validateStableContactIdentifier(value) {
|
|
13
18
|
const normalized = required(value, 'stableContactIdentifier');
|
|
14
19
|
if (!/^urn:multibase:z[1-9A-HJ-NP-Za-km-z]+$/.test(normalized)) {
|
|
@@ -46,61 +51,42 @@ export function normalizeOrganizationRoleLicensePolicies(policies) {
|
|
|
46
51
|
const seen = new Set();
|
|
47
52
|
return policies.map((policy) => {
|
|
48
53
|
const sector = normalizedSector(policy.sector);
|
|
54
|
+
if (!sector)
|
|
55
|
+
throw new TypeError('Licence sector policy requires a canonical sector.');
|
|
56
|
+
if (!Object.values(DataspaceSectors).includes(sector)) {
|
|
57
|
+
throw new TypeError(`Unsupported licence sector policy: ${sector}.`);
|
|
58
|
+
}
|
|
49
59
|
if (seen.has(sector))
|
|
50
|
-
throw new TypeError(`Duplicate licence sector policy: ${sector
|
|
60
|
+
throw new TypeError(`Duplicate licence sector policy: ${sector}.`);
|
|
51
61
|
seen.add(sector);
|
|
52
|
-
if (policy.maxDevices !==
|
|
62
|
+
if (policy.maxDevices !== undefined
|
|
53
63
|
&& (!Number.isInteger(policy.maxDevices) || policy.maxDevices < 1)) {
|
|
54
|
-
throw new TypeError('maxDevices must be
|
|
64
|
+
throw new TypeError('maxDevices must be omitted or a positive integer.');
|
|
55
65
|
}
|
|
56
|
-
return {
|
|
66
|
+
return {
|
|
67
|
+
sector,
|
|
68
|
+
active: Boolean(policy.active),
|
|
69
|
+
...(policy.maxDevices === undefined ? {} : { maxDevices: policy.maxDevices }),
|
|
70
|
+
};
|
|
57
71
|
});
|
|
58
72
|
}
|
|
59
|
-
/**
|
|
73
|
+
/** Resolves the exact canonical sector policy. */
|
|
60
74
|
export function resolveOrganizationRoleLicensePolicy(policies, sector) {
|
|
61
75
|
const requested = required(sector, 'sector').toLowerCase();
|
|
62
|
-
return policies.find((policy) => normalizedSector(policy.sector) === requested)
|
|
63
|
-
?? policies.find((policy) => normalizedSector(policy.sector) === '');
|
|
76
|
+
return policies.find((policy) => normalizedSector(policy.sector) === requested);
|
|
64
77
|
}
|
|
65
78
|
/** Returns the contractual limit or the positive GW/portal default. */
|
|
66
79
|
export function resolveOrganizationRoleLicenseMaxDevices(policy, defaultMaxDevices) {
|
|
67
|
-
if (policy.maxDevices !==
|
|
80
|
+
if (policy.maxDevices !== undefined)
|
|
68
81
|
return policy.maxDevices;
|
|
69
82
|
if (!Number.isInteger(defaultMaxDevices) || defaultMaxDevices < 1) {
|
|
70
83
|
throw new TypeError('defaultMaxDevices must be a positive integer.');
|
|
71
84
|
}
|
|
72
85
|
return defaultMaxDevices;
|
|
73
86
|
}
|
|
74
|
-
/** Checks global status plus the resolved exact
|
|
87
|
+
/** Checks global status plus the resolved exact-sector policy. */
|
|
75
88
|
export function organizationRoleLicenseAllowsSector(license, sector) {
|
|
76
89
|
if (license.status !== 'active')
|
|
77
90
|
return false;
|
|
78
91
|
return resolveOrganizationRoleLicensePolicy(license.data, sector)?.active === true;
|
|
79
92
|
}
|
|
80
|
-
/** Active DCR installations are counted per concrete sector, across hosts/apps. */
|
|
81
|
-
export function countActiveOrganizationRoleLicenseDevices(devices, sector) {
|
|
82
|
-
const requested = required(sector, 'sector').toLowerCase();
|
|
83
|
-
return devices.filter((device) => device.status === 'active'
|
|
84
|
-
&& normalizedSector(device.sector) === requested).length;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Deterministic DCR admission decision. Re-registering the same active client
|
|
88
|
-
* is idempotent and does not consume an additional device slot.
|
|
89
|
-
*/
|
|
90
|
-
export function organizationRoleLicenseAllowsDevice(license, input) {
|
|
91
|
-
const sector = required(input.sector, 'sector').toLowerCase();
|
|
92
|
-
const clientId = required(input.clientId, 'clientId');
|
|
93
|
-
const clientInstanceId = required(input.clientInstanceId, 'clientInstanceId');
|
|
94
|
-
if (!organizationRoleLicenseAllowsSector(license, sector))
|
|
95
|
-
return false;
|
|
96
|
-
if (license.devices.some((device) => device.status === 'active'
|
|
97
|
-
&& device.clientId === clientId
|
|
98
|
-
&& device.clientInstanceId === clientInstanceId
|
|
99
|
-
&& normalizedSector(device.sector) === sector))
|
|
100
|
-
return true;
|
|
101
|
-
const policy = resolveOrganizationRoleLicensePolicy(license.data, sector);
|
|
102
|
-
if (!policy)
|
|
103
|
-
return false;
|
|
104
|
-
return countActiveOrganizationRoleLicenseDevices(license.devices, sector)
|
|
105
|
-
< resolveOrganizationRoleLicenseMaxDevices(policy, input.defaultMaxDevices);
|
|
106
|
-
}
|