gdc-sdk-node-ts 2.1.1 → 2.2.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.
- package/README.md +11 -5
- package/dist/backend-profile-workspace.d.ts +48 -0
- package/dist/backend-profile-workspace.js +91 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/individual-controller-backend-runtime.d.ts +6 -1
- package/dist/individual-controller-backend-runtime.js +7 -0
- package/dist/node-runtime-client.d.ts +18 -27
- package/dist/node-runtime-client.js +230 -461
- package/dist/orchestration/client-port.d.ts +4 -2
- package/dist/orchestration/individual-controller-sdk.d.ts +42 -9
- package/dist/orchestration/individual-controller-sdk.js +48 -8
- package/dist/orchestration/individual-member-sdk.d.ts +25 -0
- package/dist/orchestration/individual-member-sdk.js +29 -0
- package/dist/orchestration/personal-sdk.d.ts +3 -1
- package/dist/orchestration/personal-sdk.js +4 -0
- package/dist/orchestration/professional-sdk.d.ts +36 -1
- package/dist/orchestration/professional-sdk.js +43 -0
- package/dist/professional-backend-runtime.d.ts +6 -1
- package/dist/professional-backend-runtime.js +7 -0
- package/dist/profile-workspace.d.ts +12 -0
- package/dist/profile-workspace.js +15 -0
- package/dist/resource-operations.d.ts +82 -25
- package/dist/resource-operations.js +190 -3
- package/dist/runtime-client-paths.d.ts +81 -0
- package/dist/runtime-client-paths.js +95 -0
- package/dist/runtime-consent.d.ts +7 -0
- package/dist/runtime-consent.js +21 -0
- package/dist/runtime-host-submission.d.ts +62 -0
- package/dist/runtime-host-submission.js +82 -0
- package/dist/runtime-http-trace.d.ts +4 -0
- package/dist/runtime-http-trace.js +44 -0
- package/dist/runtime-message.d.ts +10 -0
- package/dist/runtime-message.js +19 -0
- package/dist/runtime-paths.d.ts +12 -0
- package/dist/runtime-paths.js +41 -0
- package/dist/runtime-route-context.d.ts +20 -0
- package/dist/runtime-route-context.js +68 -0
- package/dist/runtime-transport.d.ts +22 -0
- package/dist/runtime-transport.js +91 -0
- package/dist/smart-token.d.ts +8 -29
- package/dist/smart-token.js +28 -3
- package/package.json +3 -3
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { buildLegalOrganizationVerificationGatewayRequestBundle, buildOrganizationDidBindingBundle, } from 'gdc-sdk-core-ts';
|
|
2
|
+
import { buildDidcommPlaintextTransportMetadata } from 'gdc-common-utils-ts/utils/activation-request';
|
|
3
|
+
export async function submitLegalOrganizationVerificationTransactionWithDeps(input) {
|
|
4
|
+
const thid = `organization-verification-transaction-${input.createRuntimeUuid()}`;
|
|
5
|
+
const jti = `organization-verification-transaction-jti-${input.createRuntimeUuid()}`;
|
|
6
|
+
const verificationBundle = buildLegalOrganizationVerificationGatewayRequestBundle(input.verificationInput);
|
|
7
|
+
const payload = input.wrapBundleAsGatewayTransactionMessage({
|
|
8
|
+
thid,
|
|
9
|
+
jti,
|
|
10
|
+
hostCtx: input.hostCtx,
|
|
11
|
+
bundle: verificationBundle,
|
|
12
|
+
});
|
|
13
|
+
return input.submitAndPoll(input.submitPath(input.hostCtx), input.pollPath(input.hostCtx), payload, input.pollOptions);
|
|
14
|
+
}
|
|
15
|
+
export async function submitLegalOrganizationIssueWithDeps(input) {
|
|
16
|
+
const thid = `organization-issue-${input.createRuntimeUuid()}`;
|
|
17
|
+
const jti = `organization-issue-jti-${input.createRuntimeUuid()}`;
|
|
18
|
+
const verificationBundle = buildLegalOrganizationVerificationGatewayRequestBundle(input.verificationInput);
|
|
19
|
+
const payload = input.wrapBundleAsGatewayTransactionMessage({
|
|
20
|
+
thid,
|
|
21
|
+
jti,
|
|
22
|
+
hostCtx: input.hostCtx,
|
|
23
|
+
bundle: verificationBundle,
|
|
24
|
+
});
|
|
25
|
+
return input.submitAndPoll(input.submitPath(input.hostCtx), input.pollPath(input.hostCtx), payload, input.pollOptions);
|
|
26
|
+
}
|
|
27
|
+
export async function submitOrganizationDidBindingWithDeps(input) {
|
|
28
|
+
const thid = `organization-did-binding-${input.createRuntimeUuid()}`;
|
|
29
|
+
const jti = `organization-did-binding-jti-${input.createRuntimeUuid()}`;
|
|
30
|
+
const payload = {
|
|
31
|
+
jti,
|
|
32
|
+
thid,
|
|
33
|
+
type: 'application/api+json',
|
|
34
|
+
body: buildOrganizationDidBindingBundle(input.bindingInput),
|
|
35
|
+
};
|
|
36
|
+
return input.submitAndPoll(input.organizationDidBindingPath(input.routeCtx), input.organizationDidBindingPollPath(input.routeCtx), payload, input.pollOptions);
|
|
37
|
+
}
|
|
38
|
+
export async function activateOrganizationInGatewayFromIcaProofWithDeps(input) {
|
|
39
|
+
const thid = `activate-org-${input.createRuntimeUuid()}`;
|
|
40
|
+
const activationDraft = input.activationDraftFactory({
|
|
41
|
+
vpToken: input.activationInput.vpToken,
|
|
42
|
+
controller: input.activationInput.controller,
|
|
43
|
+
service: input.activationInput.service,
|
|
44
|
+
additionalClaims: input.activationInput.additionalClaims,
|
|
45
|
+
});
|
|
46
|
+
const serviceClaims = activationDraft.buildServiceClaims();
|
|
47
|
+
const transportMeta = buildDidcommPlaintextTransportMetadata({
|
|
48
|
+
controller: input.activationInput.controller,
|
|
49
|
+
contentType: 'application/didcomm-plain+json',
|
|
50
|
+
});
|
|
51
|
+
const payload = {
|
|
52
|
+
thid,
|
|
53
|
+
iss: String(input.hostCtx.controllerDid || '').trim() || undefined,
|
|
54
|
+
aud: String(input.hostCtx.hostDid || '').trim() || undefined,
|
|
55
|
+
type: 'application/api+json',
|
|
56
|
+
...(transportMeta ? { meta: transportMeta } : {}),
|
|
57
|
+
body: {
|
|
58
|
+
vp_token: input.activationInput.vpToken,
|
|
59
|
+
...(input.activationInput.controller ? { controller: input.activationInput.controller } : {}),
|
|
60
|
+
data: [{
|
|
61
|
+
type: 'Organization-activation-request-v1.0',
|
|
62
|
+
meta: {
|
|
63
|
+
claims: {
|
|
64
|
+
'@context': 'org.schema',
|
|
65
|
+
...serviceClaims,
|
|
66
|
+
...(input.activationInput.additionalClaims || {}),
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
resource: {
|
|
70
|
+
meta: {
|
|
71
|
+
claims: {
|
|
72
|
+
'@context': 'org.schema',
|
|
73
|
+
...serviceClaims,
|
|
74
|
+
...(input.activationInput.additionalClaims || {}),
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
}],
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
return input.submitAndPoll(input.submitPath(input.hostCtx), input.pollPath(input.hostCtx), payload, input.pollOptions);
|
|
82
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function appendHttpTrace(traceFile: string | undefined, entry: Record<string, unknown>): void;
|
|
2
|
+
export declare function parseTraceBody(body: BodyInit | null | undefined): unknown;
|
|
3
|
+
export declare function parseTraceRawText(raw: string): unknown;
|
|
4
|
+
export declare function redactTraceValue<T>(value: T): T;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
export function appendHttpTrace(traceFile, entry) {
|
|
5
|
+
if (!traceFile)
|
|
6
|
+
return;
|
|
7
|
+
try {
|
|
8
|
+
fs.mkdirSync(path.dirname(traceFile), { recursive: true });
|
|
9
|
+
fs.appendFileSync(traceFile, `${JSON.stringify(entry)}\n`);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
// Tracing must never break runtime requests.
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function parseTraceBody(body) {
|
|
16
|
+
if (body == null)
|
|
17
|
+
return undefined;
|
|
18
|
+
if (typeof body === 'string')
|
|
19
|
+
return parseTraceRawText(body);
|
|
20
|
+
if (body instanceof URLSearchParams)
|
|
21
|
+
return Object.fromEntries(body.entries());
|
|
22
|
+
return '[non-text-body]';
|
|
23
|
+
}
|
|
24
|
+
export function parseTraceRawText(raw) {
|
|
25
|
+
if (!raw)
|
|
26
|
+
return '';
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(raw);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return raw;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function redactTraceValue(value) {
|
|
35
|
+
if (value === undefined)
|
|
36
|
+
return value;
|
|
37
|
+
const serialized = JSON.stringify(value, (key, nestedValue) => {
|
|
38
|
+
if (/token|authorization|secret|password/i.test(String(key || ''))) {
|
|
39
|
+
return '[redacted]';
|
|
40
|
+
}
|
|
41
|
+
return nestedValue;
|
|
42
|
+
});
|
|
43
|
+
return serialized === undefined ? value : JSON.parse(serialized);
|
|
44
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { BundleJsonApi } from 'gdc-common-utils-ts/models/bundle';
|
|
2
|
+
import type { HostRouteContext } from './host-onboarding.js';
|
|
3
|
+
import type { SubmitPayload } from './orchestration/client-port.js';
|
|
4
|
+
export declare function wrapBundleAsGatewayTransactionMessage(input: Readonly<{
|
|
5
|
+
thid: string;
|
|
6
|
+
jti: string;
|
|
7
|
+
hostCtx: HostRouteContext;
|
|
8
|
+
bundle: BundleJsonApi;
|
|
9
|
+
}>): SubmitPayload;
|
|
10
|
+
export declare function runtimeUuid(): string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import { runtimeUuid as buildRuntimeUuid } from 'gdc-common-utils-ts/utils/communication-attached-bundle-session-helpers';
|
|
3
|
+
export function wrapBundleAsGatewayTransactionMessage(input) {
|
|
4
|
+
const rawBundle = (input.bundle || {});
|
|
5
|
+
const attachments = Array.isArray(rawBundle.attachments) ? rawBundle.attachments : undefined;
|
|
6
|
+
const { attachments: _ignoredAttachments, ...body } = rawBundle;
|
|
7
|
+
return {
|
|
8
|
+
jti: input.jti,
|
|
9
|
+
thid: input.thid,
|
|
10
|
+
iss: String(input.hostCtx.controllerDid || '').trim() || undefined,
|
|
11
|
+
aud: String(input.hostCtx.hostDid || '').trim() || undefined,
|
|
12
|
+
type: 'application/api+json',
|
|
13
|
+
body,
|
|
14
|
+
...(attachments && attachments.length > 0 ? { attachments } : {}),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function runtimeUuid() {
|
|
18
|
+
return buildRuntimeUuid('runtime');
|
|
19
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { HostRouteContext } from './host-onboarding.js';
|
|
2
|
+
import type { RouteContext } from './individual-onboarding.js';
|
|
3
|
+
export declare function buildV1Path(routeCtx: RouteContext, section: string, format: string, resourceType: string, action: string): string;
|
|
4
|
+
export declare function buildHostRegistryPath(hostCtx: HostRouteContext, resourceType: string, action: string): string;
|
|
5
|
+
export declare function buildOrganizationDidBindingPath(routeCtx: RouteContext): string;
|
|
6
|
+
export declare function buildOrganizationDidBindingPollPath(routeCtx: RouteContext): string;
|
|
7
|
+
export declare function buildIdentityTokenExchangePath(ctx: RouteContext): string;
|
|
8
|
+
export declare function buildIdentityTokenExchangePollPath(ctx: RouteContext): string;
|
|
9
|
+
export declare function buildIdentityDeviceDcrPath(ctx: RouteContext): string;
|
|
10
|
+
export declare function buildIdentityDeviceDcrPollPath(ctx: RouteContext): string;
|
|
11
|
+
export declare function buildIdentityOpenIdSmartTokenPath(ctx: RouteContext): string;
|
|
12
|
+
export declare function buildIdentityOpenIdSmartTokenPollPath(ctx: RouteContext): string;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import { buildGwCoreTenantResourceActionPath } from 'gdc-common-utils-ts/utils/gw-core-path';
|
|
3
|
+
export function buildV1Path(routeCtx, section, format, resourceType, action) {
|
|
4
|
+
return buildGwCoreTenantResourceActionPath({
|
|
5
|
+
tenantId: routeCtx.tenantId,
|
|
6
|
+
jurisdiction: routeCtx.jurisdiction,
|
|
7
|
+
version: 'v1',
|
|
8
|
+
sector: routeCtx.sector,
|
|
9
|
+
section,
|
|
10
|
+
format,
|
|
11
|
+
resourceType,
|
|
12
|
+
action,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
export function buildHostRegistryPath(hostCtx, resourceType, action) {
|
|
16
|
+
return `/host/cds-${encodeURIComponent(hostCtx.jurisdiction)}/v1/${encodeURIComponent(hostCtx.hostNetwork || '')}/registry/org.schema/${encodeURIComponent(resourceType)}/${encodeURIComponent(action)}`;
|
|
17
|
+
}
|
|
18
|
+
export function buildOrganizationDidBindingPath(routeCtx) {
|
|
19
|
+
return `/${encodeURIComponent(routeCtx.tenantId)}/cds-${encodeURIComponent(routeCtx.jurisdiction)}/v1/${encodeURIComponent(routeCtx.sector)}/did/document/_binding`;
|
|
20
|
+
}
|
|
21
|
+
export function buildOrganizationDidBindingPollPath(routeCtx) {
|
|
22
|
+
return `/${encodeURIComponent(routeCtx.tenantId)}/cds-${encodeURIComponent(routeCtx.jurisdiction)}/v1/${encodeURIComponent(routeCtx.sector)}/did/document/_binding-response`;
|
|
23
|
+
}
|
|
24
|
+
export function buildIdentityTokenExchangePath(ctx) {
|
|
25
|
+
return `/${encodeURIComponent('host')}/cds-${encodeURIComponent(ctx.jurisdiction)}/v1/${encodeURIComponent(ctx.sector)}/${encodeURIComponent(ctx.tenantId)}/identity/auth/_exchange`;
|
|
26
|
+
}
|
|
27
|
+
export function buildIdentityTokenExchangePollPath(ctx) {
|
|
28
|
+
return `/${encodeURIComponent('host')}/cds-${encodeURIComponent(ctx.jurisdiction)}/v1/${encodeURIComponent(ctx.sector)}/${encodeURIComponent(ctx.tenantId)}/identity/auth/_exchange-response`;
|
|
29
|
+
}
|
|
30
|
+
export function buildIdentityDeviceDcrPath(ctx) {
|
|
31
|
+
return `/${encodeURIComponent('host')}/cds-${encodeURIComponent(ctx.jurisdiction)}/v1/${encodeURIComponent(ctx.sector)}/${encodeURIComponent(ctx.tenantId)}/identity/auth/_dcr`;
|
|
32
|
+
}
|
|
33
|
+
export function buildIdentityDeviceDcrPollPath(ctx) {
|
|
34
|
+
return `/${encodeURIComponent('host')}/cds-${encodeURIComponent(ctx.jurisdiction)}/v1/${encodeURIComponent(ctx.sector)}/${encodeURIComponent(ctx.tenantId)}/identity/auth/_dcr-response`;
|
|
35
|
+
}
|
|
36
|
+
export function buildIdentityOpenIdSmartTokenPath(ctx) {
|
|
37
|
+
return `/${encodeURIComponent(ctx.tenantId)}/cds-${encodeURIComponent(ctx.jurisdiction)}/v1/${encodeURIComponent(ctx.sector)}/identity/openid/smart/token`;
|
|
38
|
+
}
|
|
39
|
+
export function buildIdentityOpenIdSmartTokenPollPath(ctx) {
|
|
40
|
+
return `/${encodeURIComponent(ctx.tenantId)}/cds-${encodeURIComponent(ctx.jurisdiction)}/v1/${encodeURIComponent(ctx.sector)}/identity/openid/smart/_batch-response`;
|
|
41
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { HostRouteContext } from './host-onboarding.js';
|
|
2
|
+
import type { RouteContext } from './individual-onboarding.js';
|
|
3
|
+
export type HostNetworkWarningState = {
|
|
4
|
+
warnedDefaultHostNetwork: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare function requireRouteContext(ctx?: RouteContext, defaultCtx?: RouteContext): RouteContext;
|
|
7
|
+
export declare function routeCtxFromInput(input: {
|
|
8
|
+
serviceProviderDid?: string;
|
|
9
|
+
tenantId?: string;
|
|
10
|
+
jurisdiction?: string;
|
|
11
|
+
sector?: string;
|
|
12
|
+
}, defaultCtx?: RouteContext): RouteContext;
|
|
13
|
+
export declare function requireHostRouteContext(ctx: HostRouteContext | undefined, options: Readonly<{
|
|
14
|
+
defaultJurisdiction?: string;
|
|
15
|
+
defaultHostNetwork?: string;
|
|
16
|
+
defaultHostNetworkOrTenantSector?: string;
|
|
17
|
+
warningState: HostNetworkWarningState;
|
|
18
|
+
warn: (message: string) => void;
|
|
19
|
+
}>): HostRouteContext;
|
|
20
|
+
export declare function isSupportedHostNetwork(value: string): boolean;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import { extractTenantIdFromHostedDidWeb } from 'gdc-common-utils-ts';
|
|
3
|
+
let warnedServiceProviderDidRouteTenant = false;
|
|
4
|
+
export function requireRouteContext(ctx, defaultCtx) {
|
|
5
|
+
const resolved = ctx || defaultCtx;
|
|
6
|
+
const tenantId = String(resolved?.tenantId || '').trim();
|
|
7
|
+
const jurisdiction = String(resolved?.jurisdiction || '').trim();
|
|
8
|
+
const sector = String(resolved?.sector || '').trim();
|
|
9
|
+
if (!tenantId || !jurisdiction || !sector) {
|
|
10
|
+
throw new Error('Route context is required.');
|
|
11
|
+
}
|
|
12
|
+
return { tenantId, jurisdiction, sector };
|
|
13
|
+
}
|
|
14
|
+
export function routeCtxFromInput(input, defaultCtx) {
|
|
15
|
+
const explicitTenantId = String(input.tenantId || '').trim();
|
|
16
|
+
const serviceProviderDid = String(input.serviceProviderDid || '').trim();
|
|
17
|
+
let tenantId = explicitTenantId;
|
|
18
|
+
if (!tenantId && serviceProviderDid) {
|
|
19
|
+
const extractedTenantId = extractTenantIdFromHostedDidWeb(serviceProviderDid);
|
|
20
|
+
if (extractedTenantId) {
|
|
21
|
+
if (!warnedServiceProviderDidRouteTenant) {
|
|
22
|
+
warnedServiceProviderDidRouteTenant = true;
|
|
23
|
+
console.warn(`[gdc-sdk-node-ts] serviceProviderDid is a compatibility alias for route tenant ids. Pass tenantId instead. Extracted tenantId='${extractedTenantId}' from hosted did:web '${serviceProviderDid}'.`);
|
|
24
|
+
}
|
|
25
|
+
tenantId = extractedTenantId;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
tenantId = serviceProviderDid;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return requireRouteContext(tenantId && input.jurisdiction && input.sector
|
|
32
|
+
? { tenantId, jurisdiction: input.jurisdiction, sector: input.sector }
|
|
33
|
+
: undefined, defaultCtx);
|
|
34
|
+
}
|
|
35
|
+
export function requireHostRouteContext(ctx, options) {
|
|
36
|
+
const hostCtx = (ctx || {});
|
|
37
|
+
const jurisdiction = String(hostCtx.jurisdiction || options.defaultJurisdiction || '').trim();
|
|
38
|
+
const explicitHostNetwork = String(hostCtx.hostNetwork || options.defaultHostNetwork || '').trim();
|
|
39
|
+
const compatibilityHostNetwork = String(hostCtx.hostNetworkOrTenantSector
|
|
40
|
+
|| options.defaultHostNetworkOrTenantSector
|
|
41
|
+
|| '').trim();
|
|
42
|
+
const deprecatedSector = String(hostCtx.sector || '').trim();
|
|
43
|
+
if (!explicitHostNetwork && !compatibilityHostNetwork && deprecatedSector) {
|
|
44
|
+
throw new Error(`Host route context must use 'hostNetwork', not 'sector'. Received deprecated sector='${deprecatedSector}'.`);
|
|
45
|
+
}
|
|
46
|
+
const hostNetwork = String(explicitHostNetwork
|
|
47
|
+
|| compatibilityHostNetwork
|
|
48
|
+
|| '').trim();
|
|
49
|
+
if (!jurisdiction)
|
|
50
|
+
throw new Error('Host route context is required.');
|
|
51
|
+
if (!hostNetwork) {
|
|
52
|
+
if (!options.warningState.warnedDefaultHostNetwork) {
|
|
53
|
+
options.warningState.warnedDefaultHostNetwork = true;
|
|
54
|
+
options.warn("[gdc-sdk-node-ts] Missing hostNetwork in host route context. Defaulting to 'test'. Pass hostNetwork explicitly to avoid environment drift.");
|
|
55
|
+
}
|
|
56
|
+
return { jurisdiction, hostNetwork: 'test' };
|
|
57
|
+
}
|
|
58
|
+
if (!isSupportedHostNetwork(hostNetwork)) {
|
|
59
|
+
throw new Error(`Invalid hostNetwork '${hostNetwork}'. Allowed values: test, local-network, test-network, network.`);
|
|
60
|
+
}
|
|
61
|
+
return { jurisdiction, hostNetwork };
|
|
62
|
+
}
|
|
63
|
+
export function isSupportedHostNetwork(value) {
|
|
64
|
+
return (value === 'test'
|
|
65
|
+
|| value === 'local-network'
|
|
66
|
+
|| value === 'test-network'
|
|
67
|
+
|| value === 'network');
|
|
68
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type RuntimeTransportConfig = Readonly<{
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
bearerToken?: string;
|
|
4
|
+
defaultHeaders: Record<string, string>;
|
|
5
|
+
requestTimeoutMs: number;
|
|
6
|
+
httpTraceFile?: string;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function buildRuntimeHeaders(config: RuntimeTransportConfig, contentType: string): Record<string, string>;
|
|
9
|
+
export declare function pollBatchResponseWithRuntimeConfig(config: RuntimeTransportConfig, path: string, request: {
|
|
10
|
+
thid: string;
|
|
11
|
+
}): Promise<{
|
|
12
|
+
status: number;
|
|
13
|
+
body: unknown;
|
|
14
|
+
retryAfterMs?: number;
|
|
15
|
+
}>;
|
|
16
|
+
export declare function postJsonWithRuntimeConfig(config: RuntimeTransportConfig, path: string, payload: unknown, contentType: string): Promise<{
|
|
17
|
+
status: number;
|
|
18
|
+
location?: string;
|
|
19
|
+
body: unknown;
|
|
20
|
+
}>;
|
|
21
|
+
export declare function fetchWithTimeout(config: RuntimeTransportConfig, path: string, init: RequestInit): Promise<Response>;
|
|
22
|
+
export declare function parseResponseBody(response: Response): Promise<unknown>;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import { DIDCOMM_DEFAULT_ACCEPT_HEADER } from 'gdc-common-utils-ts/utils/didcomm-submit';
|
|
3
|
+
import { appendHttpTrace, parseTraceBody, parseTraceRawText, redactTraceValue, } from './runtime-http-trace.js';
|
|
4
|
+
export function buildRuntimeHeaders(config, contentType) {
|
|
5
|
+
const headers = {
|
|
6
|
+
...config.defaultHeaders,
|
|
7
|
+
'Content-Type': contentType,
|
|
8
|
+
Accept: DIDCOMM_DEFAULT_ACCEPT_HEADER,
|
|
9
|
+
};
|
|
10
|
+
if (config.bearerToken)
|
|
11
|
+
headers.Authorization = `Bearer ${config.bearerToken}`;
|
|
12
|
+
return headers;
|
|
13
|
+
}
|
|
14
|
+
export async function pollBatchResponseWithRuntimeConfig(config, path, request) {
|
|
15
|
+
const response = await fetchWithTimeout(config, path, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: buildRuntimeHeaders(config, 'application/json'),
|
|
18
|
+
body: JSON.stringify(request),
|
|
19
|
+
});
|
|
20
|
+
const retryAfter = Number(response.headers.get('retry-after'));
|
|
21
|
+
return {
|
|
22
|
+
status: response.status,
|
|
23
|
+
body: await parseResponseBody(response),
|
|
24
|
+
retryAfterMs: Number.isFinite(retryAfter) ? retryAfter * 1000 : undefined,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export async function postJsonWithRuntimeConfig(config, path, payload, contentType) {
|
|
28
|
+
const response = await fetchWithTimeout(config, path, {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: buildRuntimeHeaders(config, contentType),
|
|
31
|
+
body: JSON.stringify(payload),
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
status: response.status,
|
|
35
|
+
location: response.headers.get('location') || undefined,
|
|
36
|
+
body: await parseResponseBody(response),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export async function fetchWithTimeout(config, path, init) {
|
|
40
|
+
const controller = new AbortController();
|
|
41
|
+
const timeout = setTimeout(() => controller.abort(), config.requestTimeoutMs);
|
|
42
|
+
const url = /^https?:\/\//.test(path) ? path : `${config.baseUrl}${path.startsWith('/') ? path : `/${path}`}`;
|
|
43
|
+
const requestBody = parseTraceBody(init.body);
|
|
44
|
+
const traceBase = {
|
|
45
|
+
ts: new Date().toISOString(),
|
|
46
|
+
request: {
|
|
47
|
+
url,
|
|
48
|
+
method: String(init.method || 'GET').toUpperCase(),
|
|
49
|
+
headers: redactTraceValue(init.headers || {}),
|
|
50
|
+
body: redactTraceValue(requestBody),
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
try {
|
|
54
|
+
const response = await fetch(url, { ...init, signal: controller.signal });
|
|
55
|
+
const responseClone = response.clone();
|
|
56
|
+
const responseRaw = await responseClone.text();
|
|
57
|
+
appendHttpTrace(config.httpTraceFile, {
|
|
58
|
+
...traceBase,
|
|
59
|
+
response: {
|
|
60
|
+
status: response.status,
|
|
61
|
+
headers: redactTraceValue(Object.fromEntries(response.headers.entries())),
|
|
62
|
+
body: redactTraceValue(parseTraceRawText(responseRaw)),
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
return response;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
appendHttpTrace(config.httpTraceFile, {
|
|
69
|
+
...traceBase,
|
|
70
|
+
error: {
|
|
71
|
+
name: error instanceof Error ? error.name : 'Error',
|
|
72
|
+
message: error instanceof Error ? error.message : String(error),
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
clearTimeout(timeout);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export async function parseResponseBody(response) {
|
|
82
|
+
const raw = await response.text();
|
|
83
|
+
if (!raw)
|
|
84
|
+
return {};
|
|
85
|
+
try {
|
|
86
|
+
return JSON.parse(raw);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return raw;
|
|
90
|
+
}
|
|
91
|
+
}
|
package/dist/smart-token.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type BuildClientAssertionJwtInput } from 'gdc-common-utils-ts/utils/client-assertion';
|
|
2
|
+
import type { SmartTokenRequestContract } from 'gdc-sdk-core-ts';
|
|
1
3
|
import type { PollOptions, SubmitAndPollResult } from './orchestration/client-port.js';
|
|
2
4
|
import type { RouteContext } from './individual-onboarding.js';
|
|
3
5
|
/**
|
|
@@ -30,7 +32,7 @@ import type { RouteContext } from './individual-onboarding.js';
|
|
|
30
32
|
* Canonical payload examples for both token-exchange and OpenID4VP SMART flows
|
|
31
33
|
* live in `gdc-common-utils-ts/examples`.
|
|
32
34
|
*/
|
|
33
|
-
export type SmartTokenRequestInput = {
|
|
35
|
+
export type SmartTokenRequestInput = SmartTokenRequestContract & {
|
|
34
36
|
/**
|
|
35
37
|
* @deprecated Prefer configuring `NodeHttpClient({ ctx })`.
|
|
36
38
|
*/
|
|
@@ -46,36 +48,14 @@ export type SmartTokenRequestInput = {
|
|
|
46
48
|
/**
|
|
47
49
|
* OpenID token or subject token already obtained by the caller.
|
|
48
50
|
*/
|
|
49
|
-
idToken: string;
|
|
50
51
|
/**
|
|
51
|
-
*
|
|
52
|
+
* Optional helper input used by the Node SDK to auto-generate one
|
|
53
|
+
* `client_assertion` when the caller does not provide one explicitly.
|
|
52
54
|
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* include additional items such as `organization/Consent.cruds`.
|
|
55
|
+
* `clientId` and `audience` are resolved from the surrounding SMART request
|
|
56
|
+
* input and therefore omitted here.
|
|
56
57
|
*/
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Actor/profile DID that is requesting access.
|
|
60
|
-
*
|
|
61
|
-
* Typical values are a professional DID or a `RelatedPerson` DID. This is
|
|
62
|
-
* distinct from the `subjectDid` whose data is being accessed.
|
|
63
|
-
*/
|
|
64
|
-
actorDid?: string;
|
|
65
|
-
/**
|
|
66
|
-
* Subject/individual DID whose data is being requested.
|
|
67
|
-
*/
|
|
68
|
-
subjectDid?: string;
|
|
69
|
-
/**
|
|
70
|
-
* Optional VP token used by the OpenID4VP-based GW smart token flow.
|
|
71
|
-
*/
|
|
72
|
-
vpToken?: string;
|
|
73
|
-
/**
|
|
74
|
-
* Client/device/portal DID used as OAuth/OpenID `client_id`.
|
|
75
|
-
*/
|
|
76
|
-
clientId?: string;
|
|
77
|
-
audience?: string;
|
|
78
|
-
issuer?: string;
|
|
58
|
+
clientAssertionBuilder?: Omit<BuildClientAssertionJwtInput, 'clientId' | 'audience'>;
|
|
79
59
|
redirectUri?: string;
|
|
80
60
|
acrValues?: string;
|
|
81
61
|
codeChallenge?: string;
|
|
@@ -88,7 +68,6 @@ export type SmartTokenRequestInput = {
|
|
|
88
68
|
endpointId?: string;
|
|
89
69
|
timeoutSeconds?: number;
|
|
90
70
|
intervalSeconds?: number;
|
|
91
|
-
additionalClaims?: Record<string, unknown>;
|
|
92
71
|
};
|
|
93
72
|
export type SmartTokenExchangeResult = {
|
|
94
73
|
status: 'fetched' | 'cached' | 'failed';
|
package/dist/smart-token.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
2
|
import { HealthcareConsentPurposes } from 'gdc-common-utils-ts/constants';
|
|
3
|
+
import { buildClientAssertionJwt } from 'gdc-common-utils-ts/utils/client-assertion';
|
|
3
4
|
import { resolvePollOptionsFromSeconds } from './poll-options.js';
|
|
4
5
|
/**
|
|
5
6
|
* Executes the current GW token flow using injected transport dependencies.
|
|
@@ -25,12 +26,24 @@ export async function requestSmartTokenWithDeps(deps) {
|
|
|
25
26
|
});
|
|
26
27
|
if (deps.input.smartTokenKind === 'openid-smart') {
|
|
27
28
|
const actorDid = String(deps.input.actorDid || '').trim() || undefined;
|
|
29
|
+
const resolvedClientId = deps.input.clientId || actorDid || deps.input.subjectDid || deps.routeCtx.tenantId;
|
|
30
|
+
const resolvedAudience = deps.input.audience || deps.routeCtx.tenantId;
|
|
31
|
+
const clientAssertion = await resolveClientAssertion({
|
|
32
|
+
clientAssertion: deps.input.clientAssertion,
|
|
33
|
+
clientAssertionBuilder: deps.input.clientAssertionBuilder,
|
|
34
|
+
clientId: resolvedClientId,
|
|
35
|
+
audience: resolvedAudience,
|
|
36
|
+
});
|
|
28
37
|
const smartPayload = {
|
|
29
38
|
thid: `smart-${createRuntimeUuid()}`,
|
|
30
|
-
iss: deps.input.issuer ||
|
|
31
|
-
aud:
|
|
39
|
+
iss: deps.input.issuer || resolvedClientId || deps.routeCtx.tenantId,
|
|
40
|
+
aud: resolvedAudience,
|
|
32
41
|
body: {
|
|
33
|
-
client_id:
|
|
42
|
+
client_id: resolvedClientId,
|
|
43
|
+
...(clientAssertion ? {
|
|
44
|
+
client_assertion: clientAssertion,
|
|
45
|
+
client_assertion_type: deps.input.clientAssertionType || 'private_key_jwt',
|
|
46
|
+
} : {}),
|
|
34
47
|
redirect_uri: deps.input.redirectUri || `${deps.baseUrl}/callback`,
|
|
35
48
|
code_challenge: deps.input.codeChallenge || 'demo-code-challenge',
|
|
36
49
|
code_challenge_method: deps.input.codeChallengeMethod || 'S256',
|
|
@@ -62,6 +75,18 @@ export async function requestSmartTokenWithDeps(deps) {
|
|
|
62
75
|
const exchange = await deps.submitAndPoll(deps.identityTokenExchangePath(deps.routeCtx), deps.identityTokenExchangePollPath(deps.routeCtx), payload, pollOptions);
|
|
63
76
|
return resolveTokenExchangeResult(exchange, normalizedScopes, tokenCacheKey, deps.setTokenCache);
|
|
64
77
|
}
|
|
78
|
+
async function resolveClientAssertion(input) {
|
|
79
|
+
const explicit = String(input.clientAssertion || '').trim();
|
|
80
|
+
if (explicit)
|
|
81
|
+
return explicit;
|
|
82
|
+
if (!input.clientAssertionBuilder)
|
|
83
|
+
return undefined;
|
|
84
|
+
return buildClientAssertionJwt({
|
|
85
|
+
...input.clientAssertionBuilder,
|
|
86
|
+
clientId: input.clientId,
|
|
87
|
+
audience: input.audience,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
65
90
|
function resolveTokenExchangeResult(exchange, normalizedScopes, tokenCacheKey, setTokenCache) {
|
|
66
91
|
const exchangeBody = exchange.poll.body ?? {};
|
|
67
92
|
const accessToken = String(exchangeBody.access_token || '').trim();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdc-sdk-node-ts",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.2",
|
|
4
4
|
"description": "Next-generation Node runtime package for the GDC SDK family",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Antifraud Services Inc.",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"test:e2e:live-gw:clean": "bash ./scripts/run-live-gw-clean.sh"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"gdc-common-utils-ts": "^2.
|
|
39
|
-
"gdc-sdk-core-ts": "
|
|
38
|
+
"gdc-common-utils-ts": "^2.2.2",
|
|
39
|
+
"gdc-sdk-core-ts": "~2.2.1"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/node": "^20.14.10",
|