gdc-common-utils-ts 2.0.15 → 2.0.17

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.
@@ -0,0 +1,41 @@
1
+ import { ClaimsOfferSchemaorg, ClaimsOrderSchemaorg } from '../constants/schemaorg';
2
+ /**
3
+ * Canonical GW CORE onboarding/reissue flow identifiers for commercial
4
+ * expectations.
5
+ *
6
+ * These identifiers are intentionally flow-level, not transport-level:
7
+ * - they describe whether one GW response is expected to mint a commercial
8
+ * Offer and whether a follow-up `Order/_batch` step is part of the contract
9
+ * - they do not describe how the caller reached the flow (PDF, ICA proof,
10
+ * signed bundle, SDK facade, etc.)
11
+ */
12
+ export declare const GwCoreCommercialFlow: Readonly<{
13
+ readonly LegalOrganizationTransaction: "legal-organization-transaction";
14
+ readonly LegalOrganizationActivateLegacy: "legal-organization-activate-legacy";
15
+ readonly LegalOrganizationIssueReissue: "legal-organization-issue-reissue";
16
+ readonly IndividualOrganizationCommercial: "individual-organization-commercial";
17
+ readonly IndividualOrganizationEmbeddedRegistration: "individual-organization-embedded-registration";
18
+ }>;
19
+ export type GwCoreCommercialFlow = typeof GwCoreCommercialFlow[keyof typeof GwCoreCommercialFlow];
20
+ export type GwCoreCommercialContract = Readonly<{
21
+ flow: GwCoreCommercialFlow;
22
+ mintsOffer: boolean;
23
+ requiresOrderConfirmation: boolean;
24
+ offerClaim?: typeof ClaimsOfferSchemaorg.identifier;
25
+ orderClaim?: typeof ClaimsOrderSchemaorg.acceptedOfferIdentifier;
26
+ programmingHint: string;
27
+ }>;
28
+ /**
29
+ * Shared commercial contract table for the GW CORE onboarding/reissue flows
30
+ * that currently matter to SDKs, BFFs and route-level tests.
31
+ *
32
+ * Reading guide:
33
+ * - `mintsOffer=true` means the response is expected to expose the canonical
34
+ * commercial claim in `meta.claims['org.schema.Offer.identifier']`
35
+ * - `requiresOrderConfirmation=true` means the caller must later submit
36
+ * `Order.acceptedOffer.identifier` through `Order/_batch`
37
+ * - `mintsOffer=false` means the flow is not expected to create a new
38
+ * commercial Offer, even if it returns activation material or other claims
39
+ */
40
+ export declare const GW_CORE_COMMERCIAL_CONTRACTS: Readonly<Record<GwCoreCommercialFlow, GwCoreCommercialContract>>;
41
+ export declare function readGwCoreCommercialContract(flow: GwCoreCommercialFlow): GwCoreCommercialContract;
@@ -0,0 +1,71 @@
1
+ import { ClaimsOfferSchemaorg, ClaimsOrderSchemaorg } from '../constants/schemaorg.js';
2
+ /**
3
+ * Canonical GW CORE onboarding/reissue flow identifiers for commercial
4
+ * expectations.
5
+ *
6
+ * These identifiers are intentionally flow-level, not transport-level:
7
+ * - they describe whether one GW response is expected to mint a commercial
8
+ * Offer and whether a follow-up `Order/_batch` step is part of the contract
9
+ * - they do not describe how the caller reached the flow (PDF, ICA proof,
10
+ * signed bundle, SDK facade, etc.)
11
+ */
12
+ export const GwCoreCommercialFlow = Object.freeze({
13
+ LegalOrganizationTransaction: 'legal-organization-transaction',
14
+ LegalOrganizationActivateLegacy: 'legal-organization-activate-legacy',
15
+ LegalOrganizationIssueReissue: 'legal-organization-issue-reissue',
16
+ IndividualOrganizationCommercial: 'individual-organization-commercial',
17
+ IndividualOrganizationEmbeddedRegistration: 'individual-organization-embedded-registration',
18
+ });
19
+ /**
20
+ * Shared commercial contract table for the GW CORE onboarding/reissue flows
21
+ * that currently matter to SDKs, BFFs and route-level tests.
22
+ *
23
+ * Reading guide:
24
+ * - `mintsOffer=true` means the response is expected to expose the canonical
25
+ * commercial claim in `meta.claims['org.schema.Offer.identifier']`
26
+ * - `requiresOrderConfirmation=true` means the caller must later submit
27
+ * `Order.acceptedOffer.identifier` through `Order/_batch`
28
+ * - `mintsOffer=false` means the flow is not expected to create a new
29
+ * commercial Offer, even if it returns activation material or other claims
30
+ */
31
+ export const GW_CORE_COMMERCIAL_CONTRACTS = Object.freeze({
32
+ [GwCoreCommercialFlow.LegalOrganizationTransaction]: {
33
+ flow: GwCoreCommercialFlow.LegalOrganizationTransaction,
34
+ mintsOffer: true,
35
+ requiresOrderConfirmation: true,
36
+ offerClaim: ClaimsOfferSchemaorg.identifier,
37
+ orderClaim: ClaimsOrderSchemaorg.acceptedOfferIdentifier,
38
+ programmingHint: 'Use this for first-time legal organization onboarding; read meta.claims[org.schema.Offer.identifier] and then confirm Order/_batch.',
39
+ },
40
+ [GwCoreCommercialFlow.LegalOrganizationActivateLegacy]: {
41
+ flow: GwCoreCommercialFlow.LegalOrganizationActivateLegacy,
42
+ mintsOffer: true,
43
+ requiresOrderConfirmation: true,
44
+ offerClaim: ClaimsOfferSchemaorg.identifier,
45
+ orderClaim: ClaimsOrderSchemaorg.acceptedOfferIdentifier,
46
+ programmingHint: 'Legacy ICA-proof activation still mints one commercial Offer and still requires Order/_batch confirmation.',
47
+ },
48
+ [GwCoreCommercialFlow.LegalOrganizationIssueReissue]: {
49
+ flow: GwCoreCommercialFlow.LegalOrganizationIssueReissue,
50
+ mintsOffer: false,
51
+ requiresOrderConfirmation: false,
52
+ programmingHint: 'Use this only to reissue controller activation material for an already existing tenant; do not expect a new Offer or Order step.',
53
+ },
54
+ [GwCoreCommercialFlow.IndividualOrganizationCommercial]: {
55
+ flow: GwCoreCommercialFlow.IndividualOrganizationCommercial,
56
+ mintsOffer: true,
57
+ requiresOrderConfirmation: true,
58
+ offerClaim: ClaimsOfferSchemaorg.identifier,
59
+ orderClaim: ClaimsOrderSchemaorg.acceptedOfferIdentifier,
60
+ programmingHint: 'Use this for the family/individual commercial bootstrap facade that returns one Offer and then requires Order/_batch.',
61
+ },
62
+ [GwCoreCommercialFlow.IndividualOrganizationEmbeddedRegistration]: {
63
+ flow: GwCoreCommercialFlow.IndividualOrganizationEmbeddedRegistration,
64
+ mintsOffer: false,
65
+ requiresOrderConfirmation: false,
66
+ programmingHint: 'Use this only for embedded legacy subject registration inside an already active tenant; it signals status but does not mint a commercial Offer.',
67
+ },
68
+ });
69
+ export function readGwCoreCommercialContract(flow) {
70
+ return GW_CORE_COMMERCIAL_CONTRACTS[flow];
71
+ }
@@ -31,6 +31,8 @@ export * from './fhir-cid';
31
31
  export * from './fhir-search';
32
32
  export * from './family-organization-summary';
33
33
  export * from './gw-core-path';
34
+ export * from './gw-core-commercial-contract';
35
+ export * from './legal-organization-verification-result';
34
36
  export * from './communication-fhir-r4';
35
37
  export * from './communication-document-reference';
36
38
  export * from './communication-bundle-document-request';
@@ -31,6 +31,8 @@ export * from './fhir-cid.js';
31
31
  export * from './fhir-search.js';
32
32
  export * from './family-organization-summary.js';
33
33
  export * from './gw-core-path.js';
34
+ export * from './gw-core-commercial-contract.js';
35
+ export * from './legal-organization-verification-result.js';
34
36
  export * from './communication-fhir-r4.js';
35
37
  export * from './communication-document-reference.js';
36
38
  export * from './communication-bundle-document-request.js';
@@ -0,0 +1,37 @@
1
+ export type LegalOrganizationVerificationCredential = Record<string, unknown>;
2
+ export type LegalOrganizationVerificationCredentialPair = Readonly<{
3
+ verificationEntries: readonly unknown[];
4
+ organizationCredential: LegalOrganizationVerificationCredential;
5
+ legalRepresentativeCredential: LegalOrganizationVerificationCredential;
6
+ }>;
7
+ /**
8
+ * Returns the ICA verification entries currently projected by GW host
9
+ * legal-organization `_transaction`.
10
+ *
11
+ * Supported shapes:
12
+ * - direct `vc[]` projection on the first response entry
13
+ * - nested `resource.icaResponse.body.data[]`
14
+ * - direct ICA `_verify-response` bodies reused in tests/docs
15
+ */
16
+ export declare function getLegalOrganizationVerificationEntriesFromResponseBody(responseBody: unknown): unknown[];
17
+ /**
18
+ * Reads the organization and legal-representative credentials returned by the
19
+ * legal-organization verification flow.
20
+ */
21
+ export declare function readLegalOrganizationVerificationCredentialPairFromResponseBody(responseBody: unknown): LegalOrganizationVerificationCredentialPair;
22
+ /**
23
+ * Reads the canonical organization tax id from the verification credential
24
+ * pair and enforces agreement between organization and representative VC when
25
+ * both values are present.
26
+ */
27
+ export declare function readLegalOrganizationVerificationTaxIdFromResponseBody(responseBody: unknown): string;
28
+ /**
29
+ * Reads `credentialSubject.sameAs` from the legal-representative credential
30
+ * when present.
31
+ */
32
+ export declare function readLegalRepresentativeSameAsFromResponseBody(responseBody: unknown): string | undefined;
33
+ /**
34
+ * Reads `credentialSubject.hasCredential.material` continuity data from the
35
+ * legal-representative credential when present.
36
+ */
37
+ export declare function readLegalRepresentativeBindingFromResponseBody(responseBody: unknown): string | undefined;
@@ -0,0 +1,106 @@
1
+ import { extractCredentialSubject, extractOrganizationTaxId, extractRepresentativeCredentialBinding, extractRepresentativeMemberOfTaxId, } from './activation-policy.js';
2
+ function asObject(value) {
3
+ if (!value || typeof value !== 'object')
4
+ return undefined;
5
+ return value;
6
+ }
7
+ function asArray(value) {
8
+ return Array.isArray(value) ? value : [];
9
+ }
10
+ function findCredentialResource(entries, expectedTypeFragment, fallbackIndex) {
11
+ const byType = entries.find((entry) => {
12
+ const candidate = asObject(entry);
13
+ const typeValue = candidate?.type;
14
+ const tokens = Array.isArray(typeValue)
15
+ ? typeValue.map((token) => String(token || ''))
16
+ : [String(typeValue || '')];
17
+ return tokens.some((token) => token.includes(expectedTypeFragment));
18
+ });
19
+ const selected = asObject(byType) || asObject(entries[fallbackIndex]);
20
+ const resource = asObject(selected?.resource) || selected;
21
+ if (!resource) {
22
+ throw new Error(`Missing '${expectedTypeFragment}' verification credential in legal-organization verification response.`);
23
+ }
24
+ return resource;
25
+ }
26
+ /**
27
+ * Returns the ICA verification entries currently projected by GW host
28
+ * legal-organization `_transaction`.
29
+ *
30
+ * Supported shapes:
31
+ * - direct `vc[]` projection on the first response entry
32
+ * - nested `resource.icaResponse.body.data[]`
33
+ * - direct ICA `_verify-response` bodies reused in tests/docs
34
+ */
35
+ export function getLegalOrganizationVerificationEntriesFromResponseBody(responseBody) {
36
+ const root = asObject(responseBody) || {};
37
+ const topLevelEntries = asArray(root.data);
38
+ const bodyEntries = asArray(asObject(root.body)?.data);
39
+ const firstEntry = asObject(bodyEntries[0]) || asObject(topLevelEntries[0]) || {};
40
+ const projectedCredentials = asArray(firstEntry.vc);
41
+ if (projectedCredentials.length >= 2) {
42
+ return projectedCredentials;
43
+ }
44
+ const nestedIcaResponse = asObject(asObject(firstEntry.resource)?.icaResponse) || {};
45
+ const nestedBodyEntries = asArray(asObject(nestedIcaResponse.body)?.data);
46
+ if (nestedBodyEntries.length >= 2) {
47
+ return nestedBodyEntries;
48
+ }
49
+ const nestedTopLevelEntries = asArray(nestedIcaResponse.data);
50
+ if (nestedTopLevelEntries.length >= 2) {
51
+ return nestedTopLevelEntries;
52
+ }
53
+ if (bodyEntries.length >= 2) {
54
+ return bodyEntries;
55
+ }
56
+ if (topLevelEntries.length >= 2) {
57
+ return topLevelEntries;
58
+ }
59
+ throw new Error('Legal-organization verification response is missing ICA verification credential entries.');
60
+ }
61
+ /**
62
+ * Reads the organization and legal-representative credentials returned by the
63
+ * legal-organization verification flow.
64
+ */
65
+ export function readLegalOrganizationVerificationCredentialPairFromResponseBody(responseBody) {
66
+ const verificationEntries = getLegalOrganizationVerificationEntriesFromResponseBody(responseBody);
67
+ return {
68
+ verificationEntries,
69
+ organizationCredential: findCredentialResource(verificationEntries, 'Organization', 0),
70
+ legalRepresentativeCredential: findCredentialResource(verificationEntries, 'LegalRepresentative', 1),
71
+ };
72
+ }
73
+ /**
74
+ * Reads the canonical organization tax id from the verification credential
75
+ * pair and enforces agreement between organization and representative VC when
76
+ * both values are present.
77
+ */
78
+ export function readLegalOrganizationVerificationTaxIdFromResponseBody(responseBody) {
79
+ const pair = readLegalOrganizationVerificationCredentialPairFromResponseBody(responseBody);
80
+ const organizationTaxId = extractOrganizationTaxId(pair.organizationCredential);
81
+ const representativeTaxId = extractRepresentativeMemberOfTaxId(pair.legalRepresentativeCredential);
82
+ const resolvedTaxId = organizationTaxId || representativeTaxId;
83
+ if (!resolvedTaxId) {
84
+ throw new Error('Legal-organization verification response is missing organization tax id in both organization and representative credentials.');
85
+ }
86
+ if (organizationTaxId && representativeTaxId && organizationTaxId !== representativeTaxId) {
87
+ throw new Error('Legal-organization verification response contains mismatched organization tax ids between organization and representative credentials.');
88
+ }
89
+ return resolvedTaxId;
90
+ }
91
+ /**
92
+ * Reads `credentialSubject.sameAs` from the legal-representative credential
93
+ * when present.
94
+ */
95
+ export function readLegalRepresentativeSameAsFromResponseBody(responseBody) {
96
+ const pair = readLegalOrganizationVerificationCredentialPairFromResponseBody(responseBody);
97
+ return String(extractCredentialSubject(pair.legalRepresentativeCredential)?.sameAs || '').trim() || undefined;
98
+ }
99
+ /**
100
+ * Reads `credentialSubject.hasCredential.material` continuity data from the
101
+ * legal-representative credential when present.
102
+ */
103
+ export function readLegalRepresentativeBindingFromResponseBody(responseBody) {
104
+ const pair = readLegalOrganizationVerificationCredentialPairFromResponseBody(responseBody);
105
+ return extractRepresentativeCredentialBinding(pair.legalRepresentativeCredential);
106
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdc-common-utils-ts",
3
- "version": "2.0.15",
3
+ "version": "2.0.17",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },