gdc-common-utils-ts 1.24.1 → 2.0.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 +39 -0
- package/dist/constants/index.d.ts +1 -0
- package/dist/constants/index.js +1 -0
- package/dist/constants/profile-runtime.d.ts +33 -0
- package/dist/constants/profile-runtime.js +30 -0
- package/dist/examples/frontend-session.js +2 -1
- package/dist/examples/ica-activation-proof.d.ts +11 -4
- package/dist/examples/ica-activation-proof.js +11 -4
- package/dist/examples/index.d.ts +1 -0
- package/dist/examples/index.js +1 -0
- package/dist/examples/lifecycle.js +5 -5
- package/dist/examples/organization-controller.d.ts +0 -1
- package/dist/examples/organization-controller.js +0 -1
- package/dist/examples/profile-runtime.d.ts +16 -0
- package/dist/examples/profile-runtime.js +18 -0
- package/dist/examples/shared.d.ts +9 -0
- package/dist/examples/shared.js +9 -0
- package/dist/interfaces/Cryptography.types.d.ts +15 -0
- package/dist/models/identity-bootstrap.d.ts +9 -0
- package/dist/utils/activation-policy.d.ts +45 -1
- package/dist/utils/activation-policy.js +65 -7
- package/dist/utils/activation-request.d.ts +63 -2
- package/dist/utils/activation-request.js +82 -0
- package/dist/utils/communication-participant-search-test-data.d.ts +17 -0
- package/dist/utils/communication-participant-search-test-data.js +39 -0
- package/dist/utils/communication-participant-search.d.ts +108 -0
- package/dist/utils/communication-participant-search.js +425 -0
- package/dist/utils/communication-retention-policy.d.ts +32 -0
- package/dist/utils/communication-retention-policy.js +41 -0
- package/dist/utils/communication-search-editor.d.ts +54 -0
- package/dist/utils/communication-search-editor.js +156 -0
- package/dist/utils/fhir-search.d.ts +32 -0
- package/dist/utils/fhir-search.js +45 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/individual-organization-lifecycle.d.ts +15 -5
- package/dist/utils/individual-organization-lifecycle.js +53 -6
- package/dist/utils/interoperable-resource-operation.d.ts +4 -4
- package/dist/utils/interoperable-resource-operation.js +22 -22
- package/dist/utils/jwk-thumbprint.d.ts +40 -0
- package/dist/utils/jwk-thumbprint.js +57 -0
- package/dist/utils/legal-organization-onboarding.d.ts +97 -0
- package/dist/utils/legal-organization-onboarding.js +128 -0
- package/dist/utils/license-commercial-search.d.ts +6 -6
- package/dist/utils/license-commercial-search.js +2 -2
- package/dist/utils/license-list-search.d.ts +7 -7
- package/dist/utils/license-list-search.js +23 -23
- package/dist/utils/license-offer-order.d.ts +19 -19
- package/dist/utils/license-offer-order.js +68 -68
- package/dist/utils/organization-lifecycle.d.ts +59 -0
- package/dist/utils/organization-lifecycle.js +155 -0
- package/dist/utils/same-as.d.ts +41 -0
- package/dist/utils/same-as.js +83 -0
- package/package.json +2 -2
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { UrnPrefixes } from '../constants/urn.js';
|
|
3
|
+
function canonicalizeForThumbprint(jwk) {
|
|
4
|
+
const keys = Object.keys(jwk).sort();
|
|
5
|
+
const parts = keys.map((key) => `"${key}":${JSON.stringify(jwk[key])}`);
|
|
6
|
+
return `{${parts.join(',')}}`;
|
|
7
|
+
}
|
|
8
|
+
function toBaseThumbprintJwk(jwk) {
|
|
9
|
+
if (jwk.kty === 'EC') {
|
|
10
|
+
const { crv, x, y } = jwk;
|
|
11
|
+
if (!crv || !x || !y)
|
|
12
|
+
throw new Error('EC JWK thumbprint requires crv, x and y.');
|
|
13
|
+
return { kty: 'EC', crv, x, y };
|
|
14
|
+
}
|
|
15
|
+
if (jwk.kty === 'RSA') {
|
|
16
|
+
const { e, n } = jwk;
|
|
17
|
+
if (!e || !n)
|
|
18
|
+
throw new Error('RSA JWK thumbprint requires e and n.');
|
|
19
|
+
return { kty: 'RSA', e, n };
|
|
20
|
+
}
|
|
21
|
+
if (jwk.kty === 'OKP') {
|
|
22
|
+
const { crv, x } = jwk;
|
|
23
|
+
if (!crv || !x)
|
|
24
|
+
throw new Error('OKP JWK thumbprint requires crv and x.');
|
|
25
|
+
return { kty: 'OKP', crv, x };
|
|
26
|
+
}
|
|
27
|
+
if (jwk.kty === 'AKP') {
|
|
28
|
+
const { alg, pub } = jwk;
|
|
29
|
+
if (!alg || !pub)
|
|
30
|
+
throw new Error('AKP JWK thumbprint requires alg and pub.');
|
|
31
|
+
return { kty: 'AKP', alg, pub };
|
|
32
|
+
}
|
|
33
|
+
throw new Error(`Unsupported JWK kty for RFC7638 thumbprint: ${jwk.kty || 'unknown'}`);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Computes the RFC 7638 JWK thumbprint as a bare base64url string.
|
|
37
|
+
*
|
|
38
|
+
* Canonical fields per supported key family:
|
|
39
|
+
* - `EC`: `kty`, `crv`, `x`, `y`
|
|
40
|
+
* - `RSA`: `kty`, `e`, `n`
|
|
41
|
+
* - `OKP`: `kty`, `crv`, `x`
|
|
42
|
+
* - `AKP` / ML-DSA: `kty`, `alg`, `pub`
|
|
43
|
+
*
|
|
44
|
+
* For classical EC keys, the curve is taken from `crv`, so keys such as
|
|
45
|
+
* `secp256k1` are handled naturally through `crv: 'secp256k1'`.
|
|
46
|
+
*/
|
|
47
|
+
export function computeRfc7638JwkThumbprint(jwk) {
|
|
48
|
+
const canonical = canonicalizeForThumbprint(toBaseThumbprintJwk(jwk));
|
|
49
|
+
return createHash('sha256').update(canonical).digest('base64url');
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns the RFC 9278 thumbprint URI form:
|
|
53
|
+
* `urn:ietf:params:oauth:jwk-thumbprint:sha-256:<base64url>`
|
|
54
|
+
*/
|
|
55
|
+
export function toJwkThumbprintSha256Urn(jwk) {
|
|
56
|
+
return `${UrnPrefixes.JwkThumbprintSha256KeyId}${computeRfc7638JwkThumbprint(jwk)}`;
|
|
57
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { ClaimsOrganizationSchemaorg } from '../constants/schemaorg';
|
|
2
|
+
import { ClaimsRecord } from '../models/resource-document';
|
|
3
|
+
export type LegalOrganizationOnboardingErrorCode = 'MISSING_IDENTIFIER_OR_TAX_ID' | 'EXPLICIT_ALTERNATE_NAME_NOT_ALLOWED';
|
|
4
|
+
export type LegalOrganizationOnboardingValidationError = {
|
|
5
|
+
code: LegalOrganizationOnboardingErrorCode;
|
|
6
|
+
message: string;
|
|
7
|
+
claimPaths: string[];
|
|
8
|
+
};
|
|
9
|
+
export type ValidateLegalOrganizationOnboardingClaimsOptions = {
|
|
10
|
+
/**
|
|
11
|
+
* When `false` (default), `alternateName` is treated as a compatibility alias
|
|
12
|
+
* derived from the canonical legal identifier. Callers may still send an
|
|
13
|
+
* explicit value, but it must match the final normalized
|
|
14
|
+
* `Organization.identifier.value`.
|
|
15
|
+
*
|
|
16
|
+
* When `true`, callers may keep an explicit `alternateName` that differs from
|
|
17
|
+
* `Organization.identifier.value`.
|
|
18
|
+
*/
|
|
19
|
+
allowExplicitAlternateNameForTenantId?: boolean;
|
|
20
|
+
};
|
|
21
|
+
export type ValidateLegalOrganizationOnboardingClaimsResult = {
|
|
22
|
+
ok: boolean;
|
|
23
|
+
errors: LegalOrganizationOnboardingValidationError[];
|
|
24
|
+
missingClaims: string[];
|
|
25
|
+
normalizedClaims: ClaimsRecord;
|
|
26
|
+
derived: {
|
|
27
|
+
identifierValueFromTaxId: boolean;
|
|
28
|
+
alternateNameFromIdentifierValue: boolean;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* JSON Schema for legal-organization onboarding claims used by high-level SDK
|
|
33
|
+
* forms and assistants before they submit anything to GW CORE.
|
|
34
|
+
*
|
|
35
|
+
* Contract:
|
|
36
|
+
* - one of `Organization.identifier.value` or `Organization.taxID` must be
|
|
37
|
+
* provided
|
|
38
|
+
* - `alternateName` is optional at input time because current GW compatibility
|
|
39
|
+
* may derive it from the canonical legal identifier
|
|
40
|
+
* - callers that want stricter tenant-alias behavior must still run the
|
|
41
|
+
* validator below because JSON Schema alone cannot express the
|
|
42
|
+
* runtime option `allowExplicitAlternateNameForTenantId`
|
|
43
|
+
*/
|
|
44
|
+
export declare const LEGAL_ORGANIZATION_ONBOARDING_JSON_SCHEMA: {
|
|
45
|
+
readonly $schema: "https://json-schema.org/draft/2020-12/schema";
|
|
46
|
+
readonly $id: "https://gdc/common-utils/legal-organization-onboarding.schema.json";
|
|
47
|
+
readonly title: "Legal Organization Onboarding Claims";
|
|
48
|
+
readonly type: "object";
|
|
49
|
+
readonly properties: {
|
|
50
|
+
readonly '@context': {
|
|
51
|
+
readonly type: "string";
|
|
52
|
+
readonly enum: readonly ["org.schema"];
|
|
53
|
+
};
|
|
54
|
+
readonly "org.schema.Organization.identifier.value": {
|
|
55
|
+
readonly type: "string";
|
|
56
|
+
readonly minLength: 1;
|
|
57
|
+
readonly description: "Canonical legal identifier used by onboarding and tenant normalization.";
|
|
58
|
+
};
|
|
59
|
+
readonly "org.schema.Organization.taxID": {
|
|
60
|
+
readonly type: "string";
|
|
61
|
+
readonly minLength: 1;
|
|
62
|
+
readonly description: "Compatibility tax identifier that may backfill Organization.identifier.value.";
|
|
63
|
+
};
|
|
64
|
+
readonly "org.schema.Organization.alternateName": {
|
|
65
|
+
readonly type: "string";
|
|
66
|
+
readonly minLength: 1;
|
|
67
|
+
readonly description: "Optional compatibility alias. If omitted, callers may derive it from Organization.identifier.value.";
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
readonly oneOf: readonly [{
|
|
71
|
+
readonly required: readonly [ClaimsOrganizationSchemaorg.identifierValue];
|
|
72
|
+
}, {
|
|
73
|
+
readonly required: readonly [ClaimsOrganizationSchemaorg.taxId];
|
|
74
|
+
}];
|
|
75
|
+
readonly additionalProperties: true;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Validates and normalizes legal-organization onboarding claims for SDKs,
|
|
79
|
+
* forms, and assistant-style data collection flows.
|
|
80
|
+
*
|
|
81
|
+
* Main behavior:
|
|
82
|
+
* - requires at least one of `Organization.identifier.value` or
|
|
83
|
+
* `Organization.taxID`
|
|
84
|
+
* - if `identifier.value` is missing and `taxID` exists, copies
|
|
85
|
+
* `taxID -> identifier.value`
|
|
86
|
+
* - if `alternateName` is missing and a canonical identifier exists, copies
|
|
87
|
+
* `identifier.value -> alternateName`
|
|
88
|
+
* - when `allowExplicitAlternateNameForTenantId` is `false` (default),
|
|
89
|
+
* rejects explicit `alternateName` values that differ from the final
|
|
90
|
+
* canonical `identifier.value`
|
|
91
|
+
*
|
|
92
|
+
* The result shape is intentionally assistant-friendly:
|
|
93
|
+
* - `missingClaims` tells UI/voice flows what is still required
|
|
94
|
+
* - `normalizedClaims` shows the post-derivation claim set
|
|
95
|
+
* - `derived` explains which values were filled automatically
|
|
96
|
+
*/
|
|
97
|
+
export declare function validateLegalOrganizationOnboardingClaims(claims: ClaimsRecord, options?: ValidateLegalOrganizationOnboardingClaimsOptions): ValidateLegalOrganizationOnboardingClaimsResult;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { ClaimsOrganizationSchemaorg } from '../constants/schemaorg.js';
|
|
2
|
+
/**
|
|
3
|
+
* JSON Schema for legal-organization onboarding claims used by high-level SDK
|
|
4
|
+
* forms and assistants before they submit anything to GW CORE.
|
|
5
|
+
*
|
|
6
|
+
* Contract:
|
|
7
|
+
* - one of `Organization.identifier.value` or `Organization.taxID` must be
|
|
8
|
+
* provided
|
|
9
|
+
* - `alternateName` is optional at input time because current GW compatibility
|
|
10
|
+
* may derive it from the canonical legal identifier
|
|
11
|
+
* - callers that want stricter tenant-alias behavior must still run the
|
|
12
|
+
* validator below because JSON Schema alone cannot express the
|
|
13
|
+
* runtime option `allowExplicitAlternateNameForTenantId`
|
|
14
|
+
*/
|
|
15
|
+
export const LEGAL_ORGANIZATION_ONBOARDING_JSON_SCHEMA = {
|
|
16
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
17
|
+
$id: 'https://gdc/common-utils/legal-organization-onboarding.schema.json',
|
|
18
|
+
title: 'Legal Organization Onboarding Claims',
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
'@context': {
|
|
22
|
+
type: 'string',
|
|
23
|
+
enum: ['org.schema'],
|
|
24
|
+
},
|
|
25
|
+
[ClaimsOrganizationSchemaorg.identifierValue]: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
minLength: 1,
|
|
28
|
+
description: 'Canonical legal identifier used by onboarding and tenant normalization.',
|
|
29
|
+
},
|
|
30
|
+
[ClaimsOrganizationSchemaorg.taxId]: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
minLength: 1,
|
|
33
|
+
description: 'Compatibility tax identifier that may backfill Organization.identifier.value.',
|
|
34
|
+
},
|
|
35
|
+
[ClaimsOrganizationSchemaorg.alternateName]: {
|
|
36
|
+
type: 'string',
|
|
37
|
+
minLength: 1,
|
|
38
|
+
description: 'Optional compatibility alias. If omitted, callers may derive it from Organization.identifier.value.',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
oneOf: [
|
|
42
|
+
{ required: [ClaimsOrganizationSchemaorg.identifierValue] },
|
|
43
|
+
{ required: [ClaimsOrganizationSchemaorg.taxId] },
|
|
44
|
+
],
|
|
45
|
+
additionalProperties: true,
|
|
46
|
+
};
|
|
47
|
+
function normalizeOptionalString(value) {
|
|
48
|
+
if (typeof value !== 'string') {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
const trimmed = value.trim();
|
|
52
|
+
return trimmed.length ? trimmed : undefined;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Validates and normalizes legal-organization onboarding claims for SDKs,
|
|
56
|
+
* forms, and assistant-style data collection flows.
|
|
57
|
+
*
|
|
58
|
+
* Main behavior:
|
|
59
|
+
* - requires at least one of `Organization.identifier.value` or
|
|
60
|
+
* `Organization.taxID`
|
|
61
|
+
* - if `identifier.value` is missing and `taxID` exists, copies
|
|
62
|
+
* `taxID -> identifier.value`
|
|
63
|
+
* - if `alternateName` is missing and a canonical identifier exists, copies
|
|
64
|
+
* `identifier.value -> alternateName`
|
|
65
|
+
* - when `allowExplicitAlternateNameForTenantId` is `false` (default),
|
|
66
|
+
* rejects explicit `alternateName` values that differ from the final
|
|
67
|
+
* canonical `identifier.value`
|
|
68
|
+
*
|
|
69
|
+
* The result shape is intentionally assistant-friendly:
|
|
70
|
+
* - `missingClaims` tells UI/voice flows what is still required
|
|
71
|
+
* - `normalizedClaims` shows the post-derivation claim set
|
|
72
|
+
* - `derived` explains which values were filled automatically
|
|
73
|
+
*/
|
|
74
|
+
export function validateLegalOrganizationOnboardingClaims(claims, options = {}) {
|
|
75
|
+
const normalizedClaims = { ...(claims || {}) };
|
|
76
|
+
const errors = [];
|
|
77
|
+
const missingClaims = [];
|
|
78
|
+
const allowExplicitAlternateNameForTenantId = options.allowExplicitAlternateNameForTenantId === true;
|
|
79
|
+
const identifierValue = normalizeOptionalString(normalizedClaims[ClaimsOrganizationSchemaorg.identifierValue]);
|
|
80
|
+
const taxId = normalizeOptionalString(normalizedClaims[ClaimsOrganizationSchemaorg.taxId]);
|
|
81
|
+
const explicitAlternateName = normalizeOptionalString(normalizedClaims[ClaimsOrganizationSchemaorg.alternateName]);
|
|
82
|
+
let finalIdentifierValue = identifierValue;
|
|
83
|
+
let identifierValueFromTaxId = false;
|
|
84
|
+
let alternateNameFromIdentifierValue = false;
|
|
85
|
+
if (!finalIdentifierValue && taxId) {
|
|
86
|
+
finalIdentifierValue = taxId;
|
|
87
|
+
normalizedClaims[ClaimsOrganizationSchemaorg.identifierValue] = taxId;
|
|
88
|
+
identifierValueFromTaxId = true;
|
|
89
|
+
}
|
|
90
|
+
if (!finalIdentifierValue) {
|
|
91
|
+
missingClaims.push(ClaimsOrganizationSchemaorg.identifierValue, ClaimsOrganizationSchemaorg.taxId);
|
|
92
|
+
errors.push({
|
|
93
|
+
code: 'MISSING_IDENTIFIER_OR_TAX_ID',
|
|
94
|
+
message: 'Legal organization onboarding requires Organization.identifier.value or Organization.taxID.',
|
|
95
|
+
claimPaths: [
|
|
96
|
+
ClaimsOrganizationSchemaorg.identifierValue,
|
|
97
|
+
ClaimsOrganizationSchemaorg.taxId,
|
|
98
|
+
],
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (!explicitAlternateName && finalIdentifierValue) {
|
|
102
|
+
normalizedClaims[ClaimsOrganizationSchemaorg.alternateName] = finalIdentifierValue;
|
|
103
|
+
alternateNameFromIdentifierValue = true;
|
|
104
|
+
}
|
|
105
|
+
if (explicitAlternateName
|
|
106
|
+
&& finalIdentifierValue
|
|
107
|
+
&& !allowExplicitAlternateNameForTenantId
|
|
108
|
+
&& explicitAlternateName !== finalIdentifierValue) {
|
|
109
|
+
errors.push({
|
|
110
|
+
code: 'EXPLICIT_ALTERNATE_NAME_NOT_ALLOWED',
|
|
111
|
+
message: 'Explicit Organization.alternateName is not allowed unless it matches Organization.identifier.value or the caller enables allowExplicitAlternateNameForTenantId.',
|
|
112
|
+
claimPaths: [
|
|
113
|
+
ClaimsOrganizationSchemaorg.alternateName,
|
|
114
|
+
ClaimsOrganizationSchemaorg.identifierValue,
|
|
115
|
+
],
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
ok: errors.length === 0,
|
|
120
|
+
errors,
|
|
121
|
+
missingClaims,
|
|
122
|
+
normalizedClaims,
|
|
123
|
+
derived: {
|
|
124
|
+
identifierValueFromTaxId,
|
|
125
|
+
alternateNameFromIdentifierValue,
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
@@ -8,14 +8,14 @@ export declare const LicenseCommercialSearchOperation: Readonly<{
|
|
|
8
8
|
readonly Offer: "Offer:Search";
|
|
9
9
|
readonly Order: "Order:Search";
|
|
10
10
|
}>;
|
|
11
|
-
export type
|
|
11
|
+
export type LicenseOfferSearchState = Readonly<{
|
|
12
12
|
offerId?: string;
|
|
13
13
|
status?: string;
|
|
14
14
|
category?: string;
|
|
15
15
|
customerType?: string;
|
|
16
16
|
additionalClaims: LicenseClaims;
|
|
17
17
|
}>;
|
|
18
|
-
export type
|
|
18
|
+
export type LicenseOrderSearchState = Readonly<{
|
|
19
19
|
acceptedOfferId?: string;
|
|
20
20
|
invoiceId?: string;
|
|
21
21
|
paymentMethod?: string;
|
|
@@ -43,13 +43,13 @@ export type LicenseOrderRecord = Readonly<{
|
|
|
43
43
|
*/
|
|
44
44
|
export declare class LicenseOfferSearchEditor {
|
|
45
45
|
private draft;
|
|
46
|
-
constructor(initial?: Partial<
|
|
46
|
+
constructor(initial?: Partial<LicenseOfferSearchState>);
|
|
47
47
|
setOfferId(value: string): this;
|
|
48
48
|
setStatus(value: string): this;
|
|
49
49
|
setCategory(value: string): this;
|
|
50
50
|
setCustomerType(value: string): this;
|
|
51
51
|
mergeClaims(claims: LicenseClaims): this;
|
|
52
|
-
|
|
52
|
+
getState(): LicenseOfferSearchState;
|
|
53
53
|
buildSearchEntry(): {
|
|
54
54
|
type: string;
|
|
55
55
|
request: {
|
|
@@ -72,13 +72,13 @@ export declare class LicenseOfferSearchEditor {
|
|
|
72
72
|
*/
|
|
73
73
|
export declare class LicenseOrderSearchEditor {
|
|
74
74
|
private draft;
|
|
75
|
-
constructor(initial?: Partial<
|
|
75
|
+
constructor(initial?: Partial<LicenseOrderSearchState>);
|
|
76
76
|
setAcceptedOfferId(value: string): this;
|
|
77
77
|
setInvoiceId(value: string): this;
|
|
78
78
|
setPaymentMethod(value: string): this;
|
|
79
79
|
setStatus(value: string): this;
|
|
80
80
|
mergeClaims(claims: LicenseClaims): this;
|
|
81
|
-
|
|
81
|
+
getState(): LicenseOrderSearchState;
|
|
82
82
|
buildSearchEntry(): {
|
|
83
83
|
type: string;
|
|
84
84
|
request: {
|
|
@@ -68,7 +68,7 @@ export class LicenseOfferSearchEditor {
|
|
|
68
68
|
});
|
|
69
69
|
return this;
|
|
70
70
|
}
|
|
71
|
-
|
|
71
|
+
getState() {
|
|
72
72
|
return cloneOfferSearchDraft(this.draft);
|
|
73
73
|
}
|
|
74
74
|
buildSearchEntry() {
|
|
@@ -131,7 +131,7 @@ export class LicenseOrderSearchEditor {
|
|
|
131
131
|
});
|
|
132
132
|
return this;
|
|
133
133
|
}
|
|
134
|
-
|
|
134
|
+
getState() {
|
|
135
135
|
return cloneOrderSearchDraft(this.draft);
|
|
136
136
|
}
|
|
137
137
|
buildSearchEntry() {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { buildLicenseSearchEntry, type LicenseClaims, type LicenseSearchInput, type LicenseStatus } from './license';
|
|
2
2
|
/**
|
|
3
|
-
* High-level filter
|
|
3
|
+
* High-level filter state for license list/search screens.
|
|
4
4
|
*
|
|
5
|
-
* This
|
|
5
|
+
* This state keeps UI semantics stable even when the runtime search transport
|
|
6
6
|
* still supports only a subset of the final portal-facing filters.
|
|
7
7
|
*/
|
|
8
|
-
export type
|
|
8
|
+
export type LicenseListSearchState = Readonly<{
|
|
9
9
|
serialNumbers?: readonly string[];
|
|
10
10
|
email?: string;
|
|
11
11
|
role?: string;
|
|
@@ -49,18 +49,18 @@ export type LicenseListSummary = Readonly<{
|
|
|
49
49
|
inactive: number;
|
|
50
50
|
}>;
|
|
51
51
|
/**
|
|
52
|
-
* High-level chainable
|
|
52
|
+
* High-level chainable editor state for frontend/backend license list/search filters.
|
|
53
53
|
*
|
|
54
54
|
* Intent:
|
|
55
55
|
* - keep UI-level filters (`active`, `unused`, `assigned`, `period`) visible at
|
|
56
56
|
* the semantic layer
|
|
57
57
|
* - map the currently supported subset to the existing canonical search entry
|
|
58
|
-
* - preserve the rest in a neutral
|
|
58
|
+
* - preserve the rest in a neutral state until the final backend facade is
|
|
59
59
|
* fully converged
|
|
60
60
|
*/
|
|
61
61
|
export declare class LicenseListSearchEditor {
|
|
62
62
|
private draft;
|
|
63
|
-
constructor(initial?: Partial<
|
|
63
|
+
constructor(initial?: Partial<LicenseListSearchState>);
|
|
64
64
|
setSerialNumbers(values: readonly string[]): this;
|
|
65
65
|
setEmail(value: string): this;
|
|
66
66
|
setRole(value: string): this;
|
|
@@ -73,7 +73,7 @@ export declare class LicenseListSearchEditor {
|
|
|
73
73
|
setUnused(value: boolean): this;
|
|
74
74
|
setPeriod(start?: string, end?: string): this;
|
|
75
75
|
mergeClaims(claims: LicenseClaims): this;
|
|
76
|
-
|
|
76
|
+
getState(): LicenseListSearchState;
|
|
77
77
|
/**
|
|
78
78
|
* Returns the currently supported runtime-facing search input subset.
|
|
79
79
|
*/
|
|
@@ -8,42 +8,42 @@ function normalizeText(value) {
|
|
|
8
8
|
function cloneClaims(claims) {
|
|
9
9
|
return { ...(claims || {}) };
|
|
10
10
|
}
|
|
11
|
-
function cloneDraft(
|
|
11
|
+
function cloneDraft(state) {
|
|
12
12
|
return {
|
|
13
|
-
serialNumbers: Array.isArray(
|
|
14
|
-
email: normalizeText(
|
|
15
|
-
role: normalizeText(
|
|
16
|
-
status:
|
|
17
|
-
subjectId: normalizeText(
|
|
18
|
-
userClass: normalizeText(
|
|
19
|
-
type: normalizeText(
|
|
20
|
-
active: typeof
|
|
21
|
-
assigned: typeof
|
|
22
|
-
unused: typeof
|
|
23
|
-
periodStart: normalizeText(
|
|
24
|
-
periodEnd: normalizeText(
|
|
25
|
-
additionalClaims: cloneClaims(
|
|
13
|
+
serialNumbers: Array.isArray(state?.serialNumbers) ? [...state.serialNumbers] : undefined,
|
|
14
|
+
email: normalizeText(state?.email),
|
|
15
|
+
role: normalizeText(state?.role),
|
|
16
|
+
status: state?.status,
|
|
17
|
+
subjectId: normalizeText(state?.subjectId),
|
|
18
|
+
userClass: normalizeText(state?.userClass),
|
|
19
|
+
type: normalizeText(state?.type),
|
|
20
|
+
active: typeof state?.active === 'boolean' ? state.active : undefined,
|
|
21
|
+
assigned: typeof state?.assigned === 'boolean' ? state.assigned : undefined,
|
|
22
|
+
unused: typeof state?.unused === 'boolean' ? state.unused : undefined,
|
|
23
|
+
periodStart: normalizeText(state?.periodStart),
|
|
24
|
+
periodEnd: normalizeText(state?.periodEnd),
|
|
25
|
+
additionalClaims: cloneClaims(state?.additionalClaims),
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
function resolveStatus(
|
|
29
|
-
if (
|
|
30
|
-
return
|
|
31
|
-
if (
|
|
28
|
+
function resolveStatus(state) {
|
|
29
|
+
if (state.status)
|
|
30
|
+
return state.status;
|
|
31
|
+
if (state.active === true)
|
|
32
32
|
return LicenseStatuses.Active;
|
|
33
|
-
if (
|
|
33
|
+
if (state.active === false)
|
|
34
34
|
return LicenseStatuses.Inactive;
|
|
35
|
-
if (
|
|
35
|
+
if (state.unused === true)
|
|
36
36
|
return LicenseStatuses.Available;
|
|
37
37
|
return undefined;
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
|
-
* High-level chainable
|
|
40
|
+
* High-level chainable editor state for frontend/backend license list/search filters.
|
|
41
41
|
*
|
|
42
42
|
* Intent:
|
|
43
43
|
* - keep UI-level filters (`active`, `unused`, `assigned`, `period`) visible at
|
|
44
44
|
* the semantic layer
|
|
45
45
|
* - map the currently supported subset to the existing canonical search entry
|
|
46
|
-
* - preserve the rest in a neutral
|
|
46
|
+
* - preserve the rest in a neutral state until the final backend facade is
|
|
47
47
|
* fully converged
|
|
48
48
|
*/
|
|
49
49
|
export class LicenseListSearchEditor {
|
|
@@ -102,7 +102,7 @@ export class LicenseListSearchEditor {
|
|
|
102
102
|
});
|
|
103
103
|
return this;
|
|
104
104
|
}
|
|
105
|
-
|
|
105
|
+
getState() {
|
|
106
106
|
return cloneDraft(this.draft);
|
|
107
107
|
}
|
|
108
108
|
/**
|
|
@@ -19,7 +19,7 @@ export type LicenseOrderSummary = Readonly<{
|
|
|
19
19
|
currency?: string;
|
|
20
20
|
seats?: number;
|
|
21
21
|
}>;
|
|
22
|
-
export type
|
|
22
|
+
export type LicenseOfferOrderState = Readonly<{
|
|
23
23
|
offer: LicenseOfferPreview;
|
|
24
24
|
order: LicenseOrderSummary;
|
|
25
25
|
baseClaims: LicenseClaims;
|
|
@@ -32,25 +32,25 @@ export type LicenseOfferOrderDraft = Readonly<{
|
|
|
32
32
|
* serialization without keeping mutable editor state.
|
|
33
33
|
*/
|
|
34
34
|
export interface LicenseOfferOrderFacade {
|
|
35
|
-
|
|
36
|
-
setOfferId(
|
|
37
|
-
setAmount(
|
|
38
|
-
setCurrency(
|
|
39
|
-
setSeats(
|
|
40
|
-
setPlanName(
|
|
41
|
-
setSku(
|
|
42
|
-
setPaymentMethod(
|
|
43
|
-
setCheckoutUrl(
|
|
44
|
-
setAcceptedOfferId(
|
|
45
|
-
setPaymentUrl(
|
|
46
|
-
setInvoiceId(
|
|
47
|
-
setActivationCode(
|
|
48
|
-
setBaseClaims(
|
|
49
|
-
buildOfferClaims(
|
|
50
|
-
buildOrderClaims(
|
|
35
|
+
createState(initial?: Partial<LicenseOfferOrderState>): LicenseOfferOrderState;
|
|
36
|
+
setOfferId(state: LicenseOfferOrderState, value: string): LicenseOfferOrderState;
|
|
37
|
+
setAmount(state: LicenseOfferOrderState, value: string): LicenseOfferOrderState;
|
|
38
|
+
setCurrency(state: LicenseOfferOrderState, value: string): LicenseOfferOrderState;
|
|
39
|
+
setSeats(state: LicenseOfferOrderState, value: number): LicenseOfferOrderState;
|
|
40
|
+
setPlanName(state: LicenseOfferOrderState, value: string): LicenseOfferOrderState;
|
|
41
|
+
setSku(state: LicenseOfferOrderState, value: string): LicenseOfferOrderState;
|
|
42
|
+
setPaymentMethod(state: LicenseOfferOrderState, value: string): LicenseOfferOrderState;
|
|
43
|
+
setCheckoutUrl(state: LicenseOfferOrderState, value: string): LicenseOfferOrderState;
|
|
44
|
+
setAcceptedOfferId(state: LicenseOfferOrderState, value: string): LicenseOfferOrderState;
|
|
45
|
+
setPaymentUrl(state: LicenseOfferOrderState, value: string): LicenseOfferOrderState;
|
|
46
|
+
setInvoiceId(state: LicenseOfferOrderState, value: string): LicenseOfferOrderState;
|
|
47
|
+
setActivationCode(state: LicenseOfferOrderState, value: string): LicenseOfferOrderState;
|
|
48
|
+
setBaseClaims(state: LicenseOfferOrderState, claims: LicenseClaims): LicenseOfferOrderState;
|
|
49
|
+
buildOfferClaims(state: LicenseOfferOrderState): LicenseClaims;
|
|
50
|
+
buildOrderClaims(state: LicenseOfferOrderState): LicenseClaims;
|
|
51
51
|
readOfferPreviewFromResponseBody(body: unknown): LicenseOfferPreview;
|
|
52
52
|
readOrderSummaryFromResponseBody(body: unknown): LicenseOrderSummary;
|
|
53
|
-
createEditor(initial?: Partial<
|
|
53
|
+
createEditor(initial?: Partial<LicenseOfferOrderState>): LicenseOfferOrderEditor;
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
56
|
* Chainable editor mirroring the didactic `get/set/build/read` style used by
|
|
@@ -104,4 +104,4 @@ export declare function createLicenseOfferOrderFacade(): LicenseOfferOrderFacade
|
|
|
104
104
|
/**
|
|
105
105
|
* Creates the chainable editor shown in the 101 tests.
|
|
106
106
|
*/
|
|
107
|
-
export declare function createLicenseOfferOrderEditor(initial?: Partial<
|
|
107
|
+
export declare function createLicenseOfferOrderEditor(initial?: Partial<LicenseOfferOrderState>): LicenseOfferOrderEditor;
|