gdc-common-utils-ts 1.24.3 → 2.0.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.
Files changed (42) hide show
  1. package/README.md +39 -0
  2. package/dist/constants/index.d.ts +1 -0
  3. package/dist/constants/index.js +1 -0
  4. package/dist/constants/profile-runtime.d.ts +33 -0
  5. package/dist/constants/profile-runtime.js +30 -0
  6. package/dist/examples/frontend-session.js +2 -1
  7. package/dist/examples/ica-verify-response.d.ts +225 -0
  8. package/dist/examples/ica-verify-response.js +257 -0
  9. package/dist/examples/index.d.ts +2 -0
  10. package/dist/examples/index.js +2 -0
  11. package/dist/examples/lifecycle.js +5 -5
  12. package/dist/examples/organization-controller.d.ts +0 -1
  13. package/dist/examples/organization-controller.js +0 -1
  14. package/dist/examples/profile-runtime.d.ts +16 -0
  15. package/dist/examples/profile-runtime.js +18 -0
  16. package/dist/interfaces/Cryptography.types.d.ts +15 -0
  17. package/dist/models/identity-bootstrap.d.ts +9 -0
  18. package/dist/utils/activation-policy.d.ts +22 -3
  19. package/dist/utils/activation-policy.js +22 -3
  20. package/dist/utils/activation-request.d.ts +43 -1
  21. package/dist/utils/activation-request.js +74 -0
  22. package/dist/utils/communication-search-editor.d.ts +3 -3
  23. package/dist/utils/communication-search-editor.js +1 -1
  24. package/dist/utils/index.d.ts +3 -0
  25. package/dist/utils/index.js +3 -0
  26. package/dist/utils/individual-organization-lifecycle.d.ts +15 -5
  27. package/dist/utils/individual-organization-lifecycle.js +53 -6
  28. package/dist/utils/interoperable-resource-operation.d.ts +4 -4
  29. package/dist/utils/interoperable-resource-operation.js +22 -22
  30. package/dist/utils/jwk-thumbprint.d.ts +40 -0
  31. package/dist/utils/jwk-thumbprint.js +57 -0
  32. package/dist/utils/legal-organization-onboarding.d.ts +97 -0
  33. package/dist/utils/legal-organization-onboarding.js +128 -0
  34. package/dist/utils/license-commercial-search.d.ts +6 -6
  35. package/dist/utils/license-commercial-search.js +2 -2
  36. package/dist/utils/license-list-search.d.ts +7 -7
  37. package/dist/utils/license-list-search.js +23 -23
  38. package/dist/utils/license-offer-order.d.ts +19 -19
  39. package/dist/utils/license-offer-order.js +68 -68
  40. package/dist/utils/organization-lifecycle.d.ts +59 -0
  41. package/dist/utils/organization-lifecycle.js +155 -0
  42. package/package.json +2 -2
@@ -16,7 +16,7 @@ export declare const InteroperableLifecycleStatuses: Readonly<{
16
16
  }>;
17
17
  export type InteroperableLifecycleStatus = typeof InteroperableLifecycleStatuses[keyof typeof InteroperableLifecycleStatuses];
18
18
  export type InteroperableSearchParams = Readonly<Record<string, SearchParameterPrimitive | undefined>>;
19
- export type InteroperableResourceOperationDraft = Readonly<{
19
+ export type InteroperableResourceOperationState = Readonly<{
20
20
  resourceType: string;
21
21
  identifierClaimKey: string;
22
22
  identifierValue?: string;
@@ -45,7 +45,7 @@ export interface InteroperableResourceOperationEditor {
45
45
  mergeClaims(claims: Record<string, unknown>): InteroperableResourceOperationEditor;
46
46
  setLifecycleStatus(value: InteroperableLifecycleStatus): InteroperableResourceOperationEditor;
47
47
  importFhirResource(resource: FhirResource): InteroperableResourceOperationEditor;
48
- getDraft(): InteroperableResourceOperationDraft;
48
+ getState(): InteroperableResourceOperationState;
49
49
  getBusinessIdentifier(): string | undefined;
50
50
  getClaims(): Record<string, unknown>;
51
51
  buildLifecycleResource(): {
@@ -140,7 +140,7 @@ export declare function buildInteroperableSearchPath(resourceType: string): stri
140
140
  * - `resource.meta.status` carries lifecycle state without overloading
141
141
  * resource-specific FHIR fields such as `status` or `active`
142
142
  */
143
- export declare function buildLifecycleOperationResource(draft: InteroperableResourceOperationDraft): {
143
+ export declare function buildLifecycleOperationResource(state: InteroperableResourceOperationState): {
144
144
  resourceType: string;
145
145
  id?: string;
146
146
  identifier?: Array<{
@@ -155,4 +155,4 @@ export declare function buildLifecycleOperationResource(draft: InteroperableReso
155
155
  /**
156
156
  * Creates the shared chainable editor for search/disable/purge request shapes.
157
157
  */
158
- export declare function createInteroperableResourceOperationEditor(initial?: Partial<InteroperableResourceOperationDraft>): InteroperableResourceOperationEditor;
158
+ export declare function createInteroperableResourceOperationEditor(initial?: Partial<InteroperableResourceOperationState>): InteroperableResourceOperationEditor;
@@ -24,23 +24,23 @@ function cloneClaims(claims) {
24
24
  function resolveDefaultIdentifierClaimKey(resourceType) {
25
25
  return `${String(resourceType || '').trim()}.identifier`;
26
26
  }
27
- function normalizeDraft(draft) {
28
- const resourceType = normalizeText(draft?.resourceType) || 'Resource';
27
+ function normalizeDraft(state) {
28
+ const resourceType = normalizeText(state?.resourceType) || 'Resource';
29
29
  return {
30
30
  resourceType,
31
- identifierClaimKey: normalizeText(draft?.identifierClaimKey) || resolveDefaultIdentifierClaimKey(resourceType),
32
- identifierValue: normalizeText(draft?.identifierValue),
33
- identifierSystem: normalizeText(draft?.identifierSystem),
34
- resourceId: normalizeText(draft?.resourceId),
35
- claims: cloneClaims(draft?.claims),
36
- lifecycleStatus: draft?.lifecycleStatus,
31
+ identifierClaimKey: normalizeText(state?.identifierClaimKey) || resolveDefaultIdentifierClaimKey(resourceType),
32
+ identifierValue: normalizeText(state?.identifierValue),
33
+ identifierSystem: normalizeText(state?.identifierSystem),
34
+ resourceId: normalizeText(state?.resourceId),
35
+ claims: cloneClaims(state?.claims),
36
+ lifecycleStatus: state?.lifecycleStatus,
37
37
  };
38
38
  }
39
- function patchDraft(draft, patch) {
39
+ function patchDraft(state, patch) {
40
40
  return normalizeDraft({
41
- ...draft,
41
+ ...state,
42
42
  ...patch,
43
- claims: patch.claims ? cloneClaims(patch.claims) : cloneClaims(draft.claims),
43
+ claims: patch.claims ? cloneClaims(patch.claims) : cloneClaims(state.claims),
44
44
  });
45
45
  }
46
46
  /**
@@ -118,23 +118,23 @@ export function buildInteroperableSearchPath(resourceType) {
118
118
  * - `resource.meta.status` carries lifecycle state without overloading
119
119
  * resource-specific FHIR fields such as `status` or `active`
120
120
  */
121
- export function buildLifecycleOperationResource(draft) {
122
- const claims = cloneClaims(draft.claims);
123
- if (draft.identifierValue && !normalizeText(claims[draft.identifierClaimKey])) {
124
- claims[draft.identifierClaimKey] = draft.identifierValue;
121
+ export function buildLifecycleOperationResource(state) {
122
+ const claims = cloneClaims(state.claims);
123
+ if (state.identifierValue && !normalizeText(claims[state.identifierClaimKey])) {
124
+ claims[state.identifierClaimKey] = state.identifierValue;
125
125
  }
126
126
  return {
127
- resourceType: draft.resourceType,
128
- ...(draft.resourceId ? { id: draft.resourceId } : {}),
129
- ...(draft.identifierValue ? {
127
+ resourceType: state.resourceType,
128
+ ...(state.resourceId ? { id: state.resourceId } : {}),
129
+ ...(state.identifierValue ? {
130
130
  identifier: [{
131
- value: draft.identifierValue,
132
- ...(draft.identifierSystem ? { system: draft.identifierSystem } : {}),
131
+ value: state.identifierValue,
132
+ ...(state.identifierSystem ? { system: state.identifierSystem } : {}),
133
133
  }],
134
134
  } : {}),
135
135
  meta: {
136
136
  claims,
137
- ...(draft.lifecycleStatus ? { status: draft.lifecycleStatus } : {}),
137
+ ...(state.lifecycleStatus ? { status: state.lifecycleStatus } : {}),
138
138
  },
139
139
  };
140
140
  }
@@ -192,7 +192,7 @@ export function createInteroperableResourceOperationEditor(initial) {
192
192
  });
193
193
  return editor;
194
194
  },
195
- getDraft() {
195
+ getState() {
196
196
  return normalizeDraft(draft);
197
197
  },
198
198
  getBusinessIdentifier() {
@@ -0,0 +1,40 @@
1
+ import { PublicJwk } from '../interfaces/Cryptography.types';
2
+ /**
3
+ * Minimal RSA public JWK shape needed for RFC 7638 thumbprint derivation.
4
+ */
5
+ export type RsaPublicJwk = {
6
+ kty: 'RSA';
7
+ e: string;
8
+ n: string;
9
+ kid?: string;
10
+ alg?: string;
11
+ use?: string;
12
+ };
13
+ /**
14
+ * Public JWK shapes supported by the RFC 7638 thumbprint helpers.
15
+ *
16
+ * Notes:
17
+ * - classic EC keys are identified by `kty: 'EC'` and use `crv`, `x`, `y`
18
+ * - this includes `secp256k1`, represented as `crv: 'secp256k1'`
19
+ * - ML-DSA keys are represented in this codebase as `kty: 'AKP'` and use
20
+ * `alg` plus `pub`; they do not use `crv`
21
+ */
22
+ export type ThumbprintableJwk = PublicJwk | RsaPublicJwk;
23
+ /**
24
+ * Computes the RFC 7638 JWK thumbprint as a bare base64url string.
25
+ *
26
+ * Canonical fields per supported key family:
27
+ * - `EC`: `kty`, `crv`, `x`, `y`
28
+ * - `RSA`: `kty`, `e`, `n`
29
+ * - `OKP`: `kty`, `crv`, `x`
30
+ * - `AKP` / ML-DSA: `kty`, `alg`, `pub`
31
+ *
32
+ * For classical EC keys, the curve is taken from `crv`, so keys such as
33
+ * `secp256k1` are handled naturally through `crv: 'secp256k1'`.
34
+ */
35
+ export declare function computeRfc7638JwkThumbprint(jwk: ThumbprintableJwk): string;
36
+ /**
37
+ * Returns the RFC 9278 thumbprint URI form:
38
+ * `urn:ietf:params:oauth:jwk-thumbprint:sha-256:<base64url>`
39
+ */
40
+ export declare function toJwkThumbprintSha256Urn(jwk: ThumbprintableJwk): string;
@@ -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 LicenseOfferSearchDraft = Readonly<{
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 LicenseOrderSearchDraft = Readonly<{
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<LicenseOfferSearchDraft>);
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
- getDraft(): LicenseOfferSearchDraft;
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<LicenseOrderSearchDraft>);
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
- getDraft(): LicenseOrderSearchDraft;
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
- getDraft() {
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
- getDraft() {
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 draft for license list/search screens.
3
+ * High-level filter state for license list/search screens.
4
4
  *
5
- * This draft keeps UI semantics stable even when the runtime search transport
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 LicenseListSearchDraft = Readonly<{
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 draft for frontend/backend license list/search filters.
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 draft until the final backend facade is
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<LicenseListSearchDraft>);
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
- getDraft(): LicenseListSearchDraft;
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(draft) {
11
+ function cloneDraft(state) {
12
12
  return {
13
- serialNumbers: Array.isArray(draft?.serialNumbers) ? [...draft.serialNumbers] : undefined,
14
- email: normalizeText(draft?.email),
15
- role: normalizeText(draft?.role),
16
- status: draft?.status,
17
- subjectId: normalizeText(draft?.subjectId),
18
- userClass: normalizeText(draft?.userClass),
19
- type: normalizeText(draft?.type),
20
- active: typeof draft?.active === 'boolean' ? draft.active : undefined,
21
- assigned: typeof draft?.assigned === 'boolean' ? draft.assigned : undefined,
22
- unused: typeof draft?.unused === 'boolean' ? draft.unused : undefined,
23
- periodStart: normalizeText(draft?.periodStart),
24
- periodEnd: normalizeText(draft?.periodEnd),
25
- additionalClaims: cloneClaims(draft?.additionalClaims),
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(draft) {
29
- if (draft.status)
30
- return draft.status;
31
- if (draft.active === true)
28
+ function resolveStatus(state) {
29
+ if (state.status)
30
+ return state.status;
31
+ if (state.active === true)
32
32
  return LicenseStatuses.Active;
33
- if (draft.active === false)
33
+ if (state.active === false)
34
34
  return LicenseStatuses.Inactive;
35
- if (draft.unused === true)
35
+ if (state.unused === true)
36
36
  return LicenseStatuses.Available;
37
37
  return undefined;
38
38
  }
39
39
  /**
40
- * High-level chainable draft for frontend/backend license list/search filters.
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 draft until the final backend facade is
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
- getDraft() {
105
+ getState() {
106
106
  return cloneDraft(this.draft);
107
107
  }
108
108
  /**