gdc-common-utils-ts 2.0.18 → 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 +18 -1
- package/dist/claims/claims-helpers-allergy-intolerance.d.ts +8 -0
- package/dist/claims/claims-helpers-allergy-intolerance.js +30 -12
- package/dist/claims/claims-helpers-condition.d.ts +8 -0
- package/dist/claims/claims-helpers-condition.js +30 -12
- package/dist/claims/claims-helpers-consent.d.ts +4 -0
- package/dist/claims/claims-helpers-consent.js +15 -1
- package/dist/claims/claims-helpers-diagnostic-report.d.ts +4 -0
- package/dist/claims/claims-helpers-diagnostic-report.js +17 -2
- package/dist/claims/claims-helpers-medication-statement.d.ts +10 -2
- package/dist/claims/claims-helpers-medication-statement.js +32 -14
- package/dist/constants/didcomm.d.ts +22 -0
- package/dist/constants/didcomm.js +22 -0
- package/dist/constants/fhir-resource-types.d.ts +2 -0
- package/dist/constants/fhir-resource-types.js +1 -0
- package/dist/constants/index.d.ts +1 -0
- package/dist/constants/index.js +1 -0
- package/dist/constants/lifecycle.d.ts +2 -0
- package/dist/constants/lifecycle.js +2 -0
- package/dist/constants/verifiable-credentials.d.ts +9 -0
- package/dist/constants/verifiable-credentials.js +9 -0
- package/dist/examples/bundle-didcomm-payload.d.ts +11 -0
- package/dist/examples/bundle-didcomm-payload.js +15 -0
- package/dist/examples/communication-attached-bundle-session.js +28 -27
- package/dist/examples/communication-didcomm-payload.d.ts +39 -0
- package/dist/examples/communication-didcomm-payload.js +44 -0
- package/dist/examples/consent-access.js +2 -1
- package/dist/examples/employee.d.ts +21 -0
- package/dist/examples/employee.js +21 -0
- package/dist/examples/index.d.ts +4 -0
- package/dist/examples/index.js +4 -0
- package/dist/examples/individual-controller.d.ts +27 -0
- package/dist/examples/individual-controller.js +28 -1
- package/dist/examples/inter-tenant-access-contract.js +3 -2
- package/dist/examples/ips-bundle.js +17 -16
- package/dist/examples/lifecycle.js +13 -11
- package/dist/examples/profile-manager-mem.d.ts +45 -0
- package/dist/examples/profile-manager-mem.js +30 -0
- package/dist/examples/related-person.d.ts +14 -0
- package/dist/examples/related-person.js +18 -4
- package/dist/examples/shared.d.ts +13 -3
- package/dist/examples/shared.js +14 -4
- package/dist/examples/vital-signs.js +1 -1
- package/dist/examples/wallet-mem.d.ts +38 -0
- package/dist/examples/wallet-mem.js +42 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interfaces/IProfileOutboxRepository.d.ts +36 -0
- package/dist/interfaces/IProfileOutboxRepository.js +2 -0
- package/dist/interfaces/IWallet.d.ts +74 -0
- package/dist/interfaces/IWallet.js +2 -0
- package/dist/interfaces/IWalletQueue.d.ts +30 -0
- package/dist/interfaces/IWalletQueue.js +2 -0
- package/dist/interfaces/index.d.ts +8 -0
- package/dist/interfaces/index.js +8 -0
- package/dist/models/authority-resolution.d.ts +56 -0
- package/dist/models/authority-resolution.js +2 -0
- package/dist/models/bundle-editor-types.d.ts +89 -0
- package/dist/models/bundle-editor-types.js +45 -0
- package/dist/models/bundle.d.ts +5 -0
- package/dist/models/communication-attached-bundle-session.d.ts +195 -0
- package/dist/models/communication-attached-bundle-session.js +36 -0
- package/dist/models/confidential-storage.d.ts +2 -1
- package/dist/models/consent-rule.d.ts +11 -1
- package/dist/models/consent-rule.js +9 -1
- package/dist/models/index.d.ts +5 -0
- package/dist/models/index.js +5 -0
- package/dist/models/individual-onboarding.d.ts +18 -0
- package/dist/models/interoperable-claims/allergy-intolerance-claims.d.ts +12 -1
- package/dist/models/interoperable-claims/allergy-intolerance-claims.js +12 -1
- package/dist/models/interoperable-claims/condition-claims.d.ts +12 -1
- package/dist/models/interoperable-claims/condition-claims.js +12 -1
- package/dist/models/interoperable-claims/diagnostic-report-claims.d.ts +14 -4
- package/dist/models/interoperable-claims/diagnostic-report-claims.js +13 -3
- package/dist/models/interoperable-claims/document-reference-claims.d.ts +1 -0
- package/dist/models/interoperable-claims/document-reference-claims.js +3 -0
- package/dist/models/interoperable-claims/medication-statement-claims.d.ts +17 -0
- package/dist/models/interoperable-claims/medication-statement-claims.js +17 -0
- package/dist/models/profile-manager.d.ts +85 -0
- package/dist/models/profile-manager.js +2 -0
- package/dist/models/wallet.d.ts +59 -0
- package/dist/models/wallet.js +22 -0
- package/dist/utils/allergy-intolerance-entry-editor.d.ts +51 -0
- package/dist/utils/allergy-intolerance-entry-editor.js +55 -0
- package/dist/utils/authority-resolution.d.ts +37 -0
- package/dist/utils/authority-resolution.js +112 -0
- package/dist/utils/backend-message-manager-mem.d.ts +78 -0
- package/dist/utils/backend-message-manager-mem.js +238 -0
- package/dist/utils/bundle-didcomm-payload.d.ts +29 -0
- package/dist/utils/bundle-didcomm-payload.js +49 -0
- package/dist/utils/bundle-document-builder.d.ts +1 -0
- package/dist/utils/bundle-document-builder.js +134 -14
- package/dist/utils/bundle-editor-core.d.ts +181 -0
- package/dist/utils/bundle-editor-core.js +467 -0
- package/dist/utils/bundle-editor-helpers.d.ts +53 -0
- package/dist/utils/bundle-editor-helpers.js +146 -0
- package/dist/utils/bundle-editor-registry.d.ts +6 -0
- package/dist/utils/bundle-editor-registry.js +14 -0
- package/dist/utils/bundle-editor.d.ts +21 -722
- package/dist/utils/bundle-editor.js +21 -1601
- package/dist/utils/bundle-entry-editor.d.ts +96 -0
- package/dist/utils/bundle-entry-editor.js +305 -0
- package/dist/utils/bundle-query.d.ts +1 -0
- package/dist/utils/bundle-query.js +12 -3
- package/dist/utils/bundle-reader.d.ts +48 -0
- package/dist/utils/bundle-reader.js +175 -1
- package/dist/utils/care-plan-entry-editor.d.ts +43 -0
- package/dist/utils/care-plan-entry-editor.js +47 -0
- package/dist/utils/client-assertion.d.ts +38 -0
- package/dist/utils/client-assertion.js +113 -0
- package/dist/utils/clinical-impression-entry-editor.d.ts +43 -0
- package/dist/utils/clinical-impression-entry-editor.js +47 -0
- package/dist/utils/clinical-resource-entry-editor.d.ts +123 -0
- package/dist/utils/clinical-resource-entry-editor.js +296 -0
- package/dist/utils/communication-attached-bundle-session-helpers.d.ts +54 -0
- package/dist/utils/communication-attached-bundle-session-helpers.js +519 -0
- package/dist/utils/communication-attached-bundle-session.d.ts +87 -304
- package/dist/utils/communication-attached-bundle-session.js +175 -841
- package/dist/utils/communication-consent-access-editor.d.ts +85 -0
- package/dist/utils/communication-consent-access-editor.js +244 -0
- package/dist/utils/communication-didcomm-payload.d.ts +38 -0
- package/dist/utils/communication-didcomm-payload.js +85 -0
- package/dist/utils/communication-document-reference.d.ts +23 -0
- package/dist/utils/communication-document-reference.js +89 -0
- package/dist/utils/communication-editor.d.ts +53 -0
- package/dist/utils/communication-editor.js +97 -0
- package/dist/utils/condition-entry-editor.d.ts +30 -0
- package/dist/utils/condition-entry-editor.js +34 -0
- package/dist/utils/consent-claim-helpers.d.ts +4 -0
- package/dist/utils/consent-claim-helpers.js +15 -1
- package/dist/utils/coverage-entry-editor.d.ts +51 -0
- package/dist/utils/coverage-entry-editor.js +55 -0
- package/dist/utils/device-entry-editor.d.ts +59 -0
- package/dist/utils/device-entry-editor.js +63 -0
- package/dist/utils/device-use-statement-entry-editor.d.ts +43 -0
- package/dist/utils/device-use-statement-entry-editor.js +47 -0
- package/dist/utils/diagnostic-report-entry-editor.d.ts +74 -0
- package/dist/utils/diagnostic-report-entry-editor.js +136 -0
- package/dist/utils/did.d.ts +8 -0
- package/dist/utils/did.js +22 -0
- package/dist/utils/document-reference-entry-editor.d.ts +62 -0
- package/dist/utils/document-reference-entry-editor.js +66 -0
- package/dist/utils/employee-entry-editor.d.ts +36 -0
- package/dist/utils/employee-entry-editor.js +88 -0
- package/dist/utils/employee.d.ts +1 -0
- package/dist/utils/employee.js +2 -1
- package/dist/utils/encounter-entry-editor.d.ts +51 -0
- package/dist/utils/encounter-entry-editor.js +55 -0
- package/dist/utils/flag-entry-editor.d.ts +47 -0
- package/dist/utils/flag-entry-editor.js +51 -0
- package/dist/utils/immunization-entry-editor.d.ts +87 -0
- package/dist/utils/immunization-entry-editor.js +169 -0
- package/dist/utils/index.d.ts +15 -0
- package/dist/utils/index.js +15 -0
- package/dist/utils/individual-onboarding-acceptance-credential.d.ts +35 -0
- package/dist/utils/individual-onboarding-acceptance-credential.js +55 -0
- package/dist/utils/individual-smart.d.ts +59 -0
- package/dist/utils/individual-smart.js +135 -0
- package/dist/utils/medication-statement-entry-editor.d.ts +90 -0
- package/dist/utils/medication-statement-entry-editor.js +94 -0
- package/dist/utils/observation-component-entry-editor.d.ts +57 -0
- package/dist/utils/observation-component-entry-editor.js +105 -0
- package/dist/utils/observation-entry-editor.d.ts +29 -0
- package/dist/utils/observation-entry-editor.js +68 -0
- package/dist/utils/procedure-entry-editor.d.ts +71 -0
- package/dist/utils/procedure-entry-editor.js +75 -0
- package/dist/utils/professional-smart.d.ts +87 -0
- package/dist/utils/professional-smart.js +118 -4
- package/dist/utils/profile-manager-mem.d.ts +69 -0
- package/dist/utils/profile-manager-mem.js +79 -0
- package/dist/utils/profile-outbox-memory-repository.d.ts +34 -0
- package/dist/utils/profile-outbox-memory-repository.js +57 -0
- package/dist/utils/same-as.d.ts +40 -0
- package/dist/utils/same-as.js +72 -0
- package/dist/utils/unified-health-id.d.ts +51 -0
- package/dist/utils/unified-health-id.js +92 -0
- package/dist/utils/vital-sign-day-batch.d.ts +25 -0
- package/dist/utils/vital-sign-day-batch.js +115 -0
- package/dist/utils/vital-sign-entry-editor.d.ts +61 -0
- package/dist/utils/vital-sign-entry-editor.js +152 -0
- package/dist/utils/wallet-mem.d.ts +93 -0
- package/dist/utils/wallet-mem.js +277 -0
- package/dist/utils/wallet-memory-queue.d.ts +32 -0
- package/dist/utils/wallet-memory-queue.js +82 -0
- package/package.json +2 -1
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { IWallet } from '../interfaces/IWallet';
|
|
2
|
+
import type { IProfileOutboxRepository } from '../interfaces/IProfileOutboxRepository';
|
|
3
|
+
import type { BackendMessageResponseRecord, BackendMessageTransport, ProfileOutboxMessageRecord, QueueProfileMessageInput } from '../models/profile-manager';
|
|
4
|
+
import { type WalletQueuedMessage } from '../models/wallet';
|
|
5
|
+
export type BackendMessageManagerMemOptions = Readonly<{
|
|
6
|
+
wallet: IWallet;
|
|
7
|
+
entityId: string;
|
|
8
|
+
transport: BackendMessageTransport;
|
|
9
|
+
outboxRepository: IProfileOutboxRepository;
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* Memory-backed backend message manager that:
|
|
13
|
+
* - queues outbound payloads through `WalletMem`
|
|
14
|
+
* - packs the next pending message as DIDComm-like JWS+JWE
|
|
15
|
+
* - submits it through an injected transport
|
|
16
|
+
* - unwraps the response and indexes it by `thid`
|
|
17
|
+
*
|
|
18
|
+
* This is the lowest reusable BFF/proxy slice before actor-specific SDK
|
|
19
|
+
* facades appear.
|
|
20
|
+
*
|
|
21
|
+
* Normal deployment story:
|
|
22
|
+
* - the injected wallet is the unlocked wallet of the user profile runtime
|
|
23
|
+
* - that same profile wallet usually encrypts outbound messages and decrypts
|
|
24
|
+
* replies
|
|
25
|
+
*
|
|
26
|
+
* Optional deployment story:
|
|
27
|
+
* - one BFF/proxy may also own a separate service wallet for its own
|
|
28
|
+
* envelopes, signatures, confidential storage, or tenant-level messaging
|
|
29
|
+
* - that service wallet is a different actor and must not be confused with
|
|
30
|
+
* the user-profile wallet handled here
|
|
31
|
+
*/
|
|
32
|
+
export declare class BackendMessageManagerMem {
|
|
33
|
+
private readonly wallet;
|
|
34
|
+
private readonly entityId;
|
|
35
|
+
private readonly transport;
|
|
36
|
+
private readonly outboxRepository;
|
|
37
|
+
private readonly responsesByThread;
|
|
38
|
+
constructor(options: BackendMessageManagerMemOptions);
|
|
39
|
+
/**
|
|
40
|
+
* Queues one outbound business payload for later submission.
|
|
41
|
+
*/
|
|
42
|
+
queueMessage(input: QueueProfileMessageInput): Promise<WalletQueuedMessage>;
|
|
43
|
+
/**
|
|
44
|
+
* Returns queued messages in current priority/FIFO processing order.
|
|
45
|
+
*/
|
|
46
|
+
listQueuedMessages(): Promise<WalletQueuedMessage[]>;
|
|
47
|
+
/**
|
|
48
|
+
* Submits the next pending message through the injected transport and stores
|
|
49
|
+
* the decoded response by `thid` when one response envelope is returned.
|
|
50
|
+
*/
|
|
51
|
+
submitNextPendingMessage(recipientEncryptionJwk: Record<string, unknown>): Promise<{
|
|
52
|
+
message: WalletQueuedMessage;
|
|
53
|
+
response?: BackendMessageResponseRecord;
|
|
54
|
+
pending?: boolean;
|
|
55
|
+
}>;
|
|
56
|
+
/**
|
|
57
|
+
* Returns the latest decoded response for one DIDComm thread.
|
|
58
|
+
*/
|
|
59
|
+
getResponseByThreadId(thid: string): BackendMessageResponseRecord | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* Lists submitted message history records preserved by the outbox repository.
|
|
62
|
+
*/
|
|
63
|
+
listOutboxHistory(): Promise<ProfileOutboxMessageRecord[]>;
|
|
64
|
+
/**
|
|
65
|
+
* Polls one previously submitted asynchronous message by id.
|
|
66
|
+
*/
|
|
67
|
+
pollSubmittedMessage(messageId: string): Promise<{
|
|
68
|
+
pending: boolean;
|
|
69
|
+
response?: BackendMessageResponseRecord;
|
|
70
|
+
record: ProfileOutboxMessageRecord;
|
|
71
|
+
}>;
|
|
72
|
+
/**
|
|
73
|
+
* Reads one decoded response by thread id, first from memory and then from the repository.
|
|
74
|
+
*/
|
|
75
|
+
readResponseByThreadId(thid: string): Promise<BackendMessageResponseRecord | undefined>;
|
|
76
|
+
private persistMessageRecord;
|
|
77
|
+
private requireOutboxRecord;
|
|
78
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
// Copyright 2026 Conectate Soluciones y Aplicaciones SL under the Apache License, Version 2.0.
|
|
2
|
+
import { WalletQueueStatuses } from '../models/wallet.js';
|
|
3
|
+
function clone(value) {
|
|
4
|
+
return JSON.parse(JSON.stringify(value));
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Memory-backed backend message manager that:
|
|
8
|
+
* - queues outbound payloads through `WalletMem`
|
|
9
|
+
* - packs the next pending message as DIDComm-like JWS+JWE
|
|
10
|
+
* - submits it through an injected transport
|
|
11
|
+
* - unwraps the response and indexes it by `thid`
|
|
12
|
+
*
|
|
13
|
+
* This is the lowest reusable BFF/proxy slice before actor-specific SDK
|
|
14
|
+
* facades appear.
|
|
15
|
+
*
|
|
16
|
+
* Normal deployment story:
|
|
17
|
+
* - the injected wallet is the unlocked wallet of the user profile runtime
|
|
18
|
+
* - that same profile wallet usually encrypts outbound messages and decrypts
|
|
19
|
+
* replies
|
|
20
|
+
*
|
|
21
|
+
* Optional deployment story:
|
|
22
|
+
* - one BFF/proxy may also own a separate service wallet for its own
|
|
23
|
+
* envelopes, signatures, confidential storage, or tenant-level messaging
|
|
24
|
+
* - that service wallet is a different actor and must not be confused with
|
|
25
|
+
* the user-profile wallet handled here
|
|
26
|
+
*/
|
|
27
|
+
export class BackendMessageManagerMem {
|
|
28
|
+
wallet;
|
|
29
|
+
entityId;
|
|
30
|
+
transport;
|
|
31
|
+
outboxRepository;
|
|
32
|
+
responsesByThread = new Map();
|
|
33
|
+
constructor(options) {
|
|
34
|
+
this.wallet = options.wallet;
|
|
35
|
+
this.entityId = String(options.entityId || '').trim();
|
|
36
|
+
this.transport = options.transport;
|
|
37
|
+
this.outboxRepository = options.outboxRepository;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Queues one outbound business payload for later submission.
|
|
41
|
+
*/
|
|
42
|
+
async queueMessage(input) {
|
|
43
|
+
if (!this.wallet.enqueueMessage) {
|
|
44
|
+
throw new Error('BackendMessageManagerMem requires wallet.enqueueMessage().');
|
|
45
|
+
}
|
|
46
|
+
const thid = typeof input.payload['thid'] === 'string' ? String(input.payload['thid']) : undefined;
|
|
47
|
+
const messageType = typeof input.payload['type'] === 'string' ? String(input.payload['type']) : undefined;
|
|
48
|
+
return this.wallet.enqueueMessage({
|
|
49
|
+
payload: input.payload,
|
|
50
|
+
priority: input.priority,
|
|
51
|
+
thid,
|
|
52
|
+
messageType,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Returns queued messages in current priority/FIFO processing order.
|
|
57
|
+
*/
|
|
58
|
+
async listQueuedMessages() {
|
|
59
|
+
if (!this.wallet.listMessages) {
|
|
60
|
+
throw new Error('BackendMessageManagerMem requires wallet.listMessages().');
|
|
61
|
+
}
|
|
62
|
+
return this.wallet.listMessages();
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Submits the next pending message through the injected transport and stores
|
|
66
|
+
* the decoded response by `thid` when one response envelope is returned.
|
|
67
|
+
*/
|
|
68
|
+
async submitNextPendingMessage(recipientEncryptionJwk) {
|
|
69
|
+
if (!this.wallet.peekNextMessage) {
|
|
70
|
+
throw new Error('BackendMessageManagerMem requires wallet.peekNextMessage().');
|
|
71
|
+
}
|
|
72
|
+
if (!this.wallet.pack) {
|
|
73
|
+
throw new Error('BackendMessageManagerMem requires wallet.pack().');
|
|
74
|
+
}
|
|
75
|
+
if (!this.wallet.markMessageDelivered || !this.wallet.markMessageFailed) {
|
|
76
|
+
throw new Error('BackendMessageManagerMem requires wallet.markMessageDelivered() and wallet.markMessageFailed().');
|
|
77
|
+
}
|
|
78
|
+
const next = await this.wallet.peekNextMessage();
|
|
79
|
+
if (!next || next.status !== WalletQueueStatuses.Pending) {
|
|
80
|
+
throw new Error('BackendMessageManagerMem found no pending queued message.');
|
|
81
|
+
}
|
|
82
|
+
const envelope = await this.wallet.pack(next.payload, recipientEncryptionJwk, this.entityId);
|
|
83
|
+
const transportResult = await this.transport.submit({
|
|
84
|
+
message: next,
|
|
85
|
+
envelope,
|
|
86
|
+
});
|
|
87
|
+
if (!transportResult.accepted) {
|
|
88
|
+
const failed = await this.wallet.markMessageFailed(next.id, String(transportResult.errorMessage || 'transport rejected queued message'));
|
|
89
|
+
await this.persistMessageRecord(failed, envelope, undefined, {
|
|
90
|
+
transportStatus: 'failed',
|
|
91
|
+
});
|
|
92
|
+
return { message: failed };
|
|
93
|
+
}
|
|
94
|
+
const delivered = await this.wallet.markMessageDelivered(next.id);
|
|
95
|
+
if (!transportResult.responseEnvelope) {
|
|
96
|
+
await this.persistMessageRecord(delivered, envelope, undefined, {
|
|
97
|
+
transportStatus: 'submitted',
|
|
98
|
+
locationUrl: transportResult.locationUrl,
|
|
99
|
+
pollCount: 0,
|
|
100
|
+
});
|
|
101
|
+
return { message: delivered, pending: true };
|
|
102
|
+
}
|
|
103
|
+
if (!this.wallet.unpack) {
|
|
104
|
+
throw new Error('BackendMessageManagerMem requires wallet.unpack() to decode response envelopes.');
|
|
105
|
+
}
|
|
106
|
+
const unpacked = await this.wallet.unpack(transportResult.responseEnvelope, this.entityId);
|
|
107
|
+
const responseContent = clone(unpacked.content);
|
|
108
|
+
const thid = String(responseContent['thid'] || delivered.thid || delivered.id).trim();
|
|
109
|
+
const response = {
|
|
110
|
+
thid,
|
|
111
|
+
receivedAt: new Date().toISOString(),
|
|
112
|
+
content: responseContent,
|
|
113
|
+
meta: clone(unpacked.meta),
|
|
114
|
+
};
|
|
115
|
+
this.responsesByThread.set(thid, response);
|
|
116
|
+
await this.outboxRepository.putResponse(response);
|
|
117
|
+
await this.persistMessageRecord(delivered, envelope, response.thid, {
|
|
118
|
+
transportStatus: 'completed',
|
|
119
|
+
});
|
|
120
|
+
return {
|
|
121
|
+
message: delivered,
|
|
122
|
+
response,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Returns the latest decoded response for one DIDComm thread.
|
|
127
|
+
*/
|
|
128
|
+
getResponseByThreadId(thid) {
|
|
129
|
+
const normalizedThreadId = String(thid || '').trim();
|
|
130
|
+
const stored = this.responsesByThread.get(normalizedThreadId);
|
|
131
|
+
return stored ? clone(stored) : undefined;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Lists submitted message history records preserved by the outbox repository.
|
|
135
|
+
*/
|
|
136
|
+
async listOutboxHistory() {
|
|
137
|
+
return this.outboxRepository.listMessages();
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Polls one previously submitted asynchronous message by id.
|
|
141
|
+
*/
|
|
142
|
+
async pollSubmittedMessage(messageId) {
|
|
143
|
+
if (!this.transport.poll) {
|
|
144
|
+
throw new Error('BackendMessageManagerMem requires transport.poll() for asynchronous polling.');
|
|
145
|
+
}
|
|
146
|
+
const currentRecord = await this.requireOutboxRecord(messageId);
|
|
147
|
+
const pollResult = await this.transport.poll({
|
|
148
|
+
message: currentRecord,
|
|
149
|
+
});
|
|
150
|
+
if (pollResult.pending) {
|
|
151
|
+
const pendingRecord = await this.outboxRepository.putMessage({
|
|
152
|
+
...currentRecord,
|
|
153
|
+
transportStatus: 'submitted',
|
|
154
|
+
pollCount: (currentRecord.pollCount || 0) + 1,
|
|
155
|
+
recordedAt: new Date().toISOString(),
|
|
156
|
+
});
|
|
157
|
+
return {
|
|
158
|
+
pending: true,
|
|
159
|
+
record: pendingRecord,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (!pollResult.completed || !pollResult.responseEnvelope) {
|
|
163
|
+
const failedRecord = await this.outboxRepository.putMessage({
|
|
164
|
+
...currentRecord,
|
|
165
|
+
transportStatus: pollResult.retryable ? 'submitted' : 'failed',
|
|
166
|
+
pollCount: (currentRecord.pollCount || 0) + 1,
|
|
167
|
+
recordedAt: new Date().toISOString(),
|
|
168
|
+
});
|
|
169
|
+
return {
|
|
170
|
+
pending: Boolean(pollResult.retryable),
|
|
171
|
+
record: failedRecord,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
if (!this.wallet.unpack) {
|
|
175
|
+
throw new Error('BackendMessageManagerMem requires wallet.unpack() to decode polled response envelopes.');
|
|
176
|
+
}
|
|
177
|
+
const unpacked = await this.wallet.unpack(pollResult.responseEnvelope, this.entityId);
|
|
178
|
+
const responseContent = clone(unpacked.content);
|
|
179
|
+
const thid = String(responseContent['thid'] || currentRecord.thid || currentRecord.id).trim();
|
|
180
|
+
const response = {
|
|
181
|
+
thid,
|
|
182
|
+
receivedAt: new Date().toISOString(),
|
|
183
|
+
content: responseContent,
|
|
184
|
+
meta: clone(unpacked.meta),
|
|
185
|
+
};
|
|
186
|
+
this.responsesByThread.set(thid, response);
|
|
187
|
+
await this.outboxRepository.putResponse(response);
|
|
188
|
+
const completedRecord = await this.outboxRepository.putMessage({
|
|
189
|
+
...currentRecord,
|
|
190
|
+
transportStatus: 'completed',
|
|
191
|
+
responseThid: response.thid,
|
|
192
|
+
pollCount: (currentRecord.pollCount || 0) + 1,
|
|
193
|
+
recordedAt: new Date().toISOString(),
|
|
194
|
+
});
|
|
195
|
+
return {
|
|
196
|
+
pending: false,
|
|
197
|
+
response,
|
|
198
|
+
record: completedRecord,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Reads one decoded response by thread id, first from memory and then from the repository.
|
|
203
|
+
*/
|
|
204
|
+
async readResponseByThreadId(thid) {
|
|
205
|
+
const inMemory = this.getResponseByThreadId(thid);
|
|
206
|
+
if (inMemory)
|
|
207
|
+
return inMemory;
|
|
208
|
+
const stored = await this.outboxRepository.getLatestResponseByThreadId(thid);
|
|
209
|
+
if (stored) {
|
|
210
|
+
this.responsesByThread.set(String(stored.thid || '').trim(), clone(stored));
|
|
211
|
+
}
|
|
212
|
+
return stored;
|
|
213
|
+
}
|
|
214
|
+
async persistMessageRecord(message, envelope, responseThid, options = {}) {
|
|
215
|
+
await this.outboxRepository.putMessage({
|
|
216
|
+
id: message.id,
|
|
217
|
+
thid: message.thid,
|
|
218
|
+
messageType: message.messageType,
|
|
219
|
+
priority: message.priority,
|
|
220
|
+
status: message.status,
|
|
221
|
+
transportStatus: options.transportStatus,
|
|
222
|
+
recordedAt: new Date().toISOString(),
|
|
223
|
+
payload: clone(message.payload),
|
|
224
|
+
envelope,
|
|
225
|
+
...(responseThid ? { responseThid } : {}),
|
|
226
|
+
...(options.locationUrl ? { locationUrl: options.locationUrl } : {}),
|
|
227
|
+
...(typeof options.pollCount === 'number' ? { pollCount: options.pollCount } : {}),
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
async requireOutboxRecord(messageId) {
|
|
231
|
+
const normalizedMessageId = String(messageId || '').trim();
|
|
232
|
+
const stored = await this.outboxRepository.getMessage(normalizedMessageId);
|
|
233
|
+
if (!stored) {
|
|
234
|
+
throw new Error(`BackendMessageManagerMem outbox record not found: ${normalizedMessageId}`);
|
|
235
|
+
}
|
|
236
|
+
return stored;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { IDecodedDidcommPayload } from '../models/confidential-message';
|
|
2
|
+
export declare const BundleDidcommEntryTypes: Readonly<{
|
|
3
|
+
readonly Batch: "Bundle-batch-request-v1.0";
|
|
4
|
+
readonly Document: "Bundle-document-request-v1.0";
|
|
5
|
+
}>;
|
|
6
|
+
/**
|
|
7
|
+
* Input contract for wrapping one bundle-like resource as one low-level
|
|
8
|
+
* DIDComm-style batch payload.
|
|
9
|
+
*/
|
|
10
|
+
export type BuildDidcommPayloadFromBundleInput = Readonly<{
|
|
11
|
+
bundle: Record<string, unknown>;
|
|
12
|
+
iss: string;
|
|
13
|
+
aud: string;
|
|
14
|
+
jti: string;
|
|
15
|
+
thid: string;
|
|
16
|
+
entryType?: string;
|
|
17
|
+
}>;
|
|
18
|
+
/**
|
|
19
|
+
* Builds one low-level DIDComm-style payload carrying one direct `Bundle`
|
|
20
|
+
* resource in `body.data[0].resource`.
|
|
21
|
+
*
|
|
22
|
+
* This path is meant for operational bundles such as employee/search/purge
|
|
23
|
+
* flows that travel as a bundle itself, not nested inside a `Communication`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildDidcommPayloadFromBundle(input: BuildDidcommPayloadFromBundleInput): IDecodedDidcommPayload;
|
|
26
|
+
/**
|
|
27
|
+
* Reads the first `Bundle` resource carried under `body.data[0].resource`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getFirstBundleResourceFromDidcommPayload(payload: IDecodedDidcommPayload): Record<string, unknown>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Copyright 2026 Conectate Soluciones y Aplicaciones SL under the Apache License, Version 2.0.
|
|
2
|
+
import { DidcommMessageTypes } from '../constants/didcomm.js';
|
|
3
|
+
export const BundleDidcommEntryTypes = Object.freeze({
|
|
4
|
+
Batch: DidcommMessageTypes.BundleBatchRequest,
|
|
5
|
+
Document: DidcommMessageTypes.BundleDocumentRequest,
|
|
6
|
+
});
|
|
7
|
+
function clone(value) {
|
|
8
|
+
return JSON.parse(JSON.stringify(value));
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Builds one low-level DIDComm-style payload carrying one direct `Bundle`
|
|
12
|
+
* resource in `body.data[0].resource`.
|
|
13
|
+
*
|
|
14
|
+
* This path is meant for operational bundles such as employee/search/purge
|
|
15
|
+
* flows that travel as a bundle itself, not nested inside a `Communication`.
|
|
16
|
+
*/
|
|
17
|
+
export function buildDidcommPayloadFromBundle(input) {
|
|
18
|
+
return {
|
|
19
|
+
iss: String(input.iss || '').trim(),
|
|
20
|
+
aud: String(input.aud || '').trim(),
|
|
21
|
+
jti: String(input.jti || '').trim(),
|
|
22
|
+
thid: String(input.thid || '').trim(),
|
|
23
|
+
type: String(input.entryType || BundleDidcommEntryTypes.Batch).trim(),
|
|
24
|
+
body: {
|
|
25
|
+
data: [
|
|
26
|
+
{
|
|
27
|
+
id: String(input.jti || '').trim(),
|
|
28
|
+
type: String(input.entryType || BundleDidcommEntryTypes.Batch).trim(),
|
|
29
|
+
resource: clone(input.bundle),
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Reads the first `Bundle` resource carried under `body.data[0].resource`.
|
|
37
|
+
*/
|
|
38
|
+
export function getFirstBundleResourceFromDidcommPayload(payload) {
|
|
39
|
+
const first = Array.isArray(payload?.body?.data)
|
|
40
|
+
? payload.body.data[0]
|
|
41
|
+
: undefined;
|
|
42
|
+
const resource = first?.resource && typeof first.resource === 'object'
|
|
43
|
+
? clone(first.resource)
|
|
44
|
+
: {};
|
|
45
|
+
if (String(resource['resourceType'] || '').trim() !== 'Bundle') {
|
|
46
|
+
throw new Error('getFirstBundleResourceFromDidcommPayload requires body.data[0].resource.resourceType = Bundle.');
|
|
47
|
+
}
|
|
48
|
+
return resource;
|
|
49
|
+
}
|
|
@@ -4,6 +4,7 @@ export type BuildBundleDocumentFromClaimsInput = Readonly<{
|
|
|
4
4
|
claimsList: readonly BundleDocumentClaims[];
|
|
5
5
|
subjectDid?: string;
|
|
6
6
|
compositionType?: string;
|
|
7
|
+
compositionClaims?: BundleDocumentClaims;
|
|
7
8
|
}>;
|
|
8
9
|
export type ValidateBundleDocumentResult = Readonly<{
|
|
9
10
|
ok: boolean;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { ResourceTypesFhirR4 } from '../constants/fhir-resource-types.js';
|
|
2
|
+
import { AllergyIntoleranceClaim } from '../models/interoperable-claims/allergy-intolerance-claims.js';
|
|
3
|
+
import { CompositionClaim } from '../models/interoperable-claims/composition-claims.js';
|
|
4
|
+
import { ConditionClaim } from '../models/interoperable-claims/condition-claims.js';
|
|
5
|
+
import { DiagnosticReportClaim } from '../models/interoperable-claims/diagnostic-report-claims.js';
|
|
6
|
+
import { MedicationStatementClaim } from '../models/interoperable-claims/medication-statement-claims.js';
|
|
7
|
+
import { ClaimConsent } from '../models/consent-rule.js';
|
|
2
8
|
import { allergyIntoleranceFlatToFhirR4, appointmentFlatToFhirR4, carePlanFlatToFhirR4, clinicalImpressionFlatToFhirR4, compositionFlatToFhirR4, conditionFlatToFhirR4, convertFhirResourceToClaims, coverageFlatToFhirR4, deviceFlatToFhirR4, documentReferenceFlatToFhirR4, diagnosticReportFlatToFhirR4, encounterFlatToFhirR4, flagFlatToFhirR4, flatClaimsToFhirResource, immunizationFlatToFhirR4, locationFlatToFhirR4, medicationStatementFlatToFhirR4, observationFromFlatToFhirR4, organizationFlatToFhirR4, procedureFlatToFhirR4, relatedPersonFlatToFhirR4, } from './clinical-resource-converters.js';
|
|
3
9
|
function asTrimmedString(value) {
|
|
4
10
|
if (value === undefined || value === null)
|
|
@@ -93,6 +99,43 @@ function normalizeSectionCode(value) {
|
|
|
93
99
|
return { code: system };
|
|
94
100
|
return { system, code };
|
|
95
101
|
}
|
|
102
|
+
function resolveContainedReferenceListClaimKey(resourceType) {
|
|
103
|
+
switch (resourceType) {
|
|
104
|
+
case ResourceTypesFhirR4.MedicationStatement:
|
|
105
|
+
return MedicationStatementClaim.ContainedReferenceList;
|
|
106
|
+
case ResourceTypesFhirR4.AllergyIntolerance:
|
|
107
|
+
return AllergyIntoleranceClaim.ContainedReferenceList;
|
|
108
|
+
case ResourceTypesFhirR4.Condition:
|
|
109
|
+
return ConditionClaim.ContainedReferenceList;
|
|
110
|
+
case ResourceTypesFhirR4.DiagnosticReport:
|
|
111
|
+
return DiagnosticReportClaim.ContainedReferenceList;
|
|
112
|
+
case ResourceTypesFhirR4.Consent:
|
|
113
|
+
return ClaimConsent.containedReferenceList;
|
|
114
|
+
default:
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function resolveContainedFlagClaimKey(resourceType) {
|
|
119
|
+
const normalized = asTrimmedString(resourceType);
|
|
120
|
+
return normalized ? `${normalized}.is-contained` : undefined;
|
|
121
|
+
}
|
|
122
|
+
function resolveContainedParentReferenceClaimKey(resourceType) {
|
|
123
|
+
const normalized = asTrimmedString(resourceType);
|
|
124
|
+
return normalized ? `${normalized}.contained-parent-reference` : undefined;
|
|
125
|
+
}
|
|
126
|
+
function mergeContainedResourceReferenceList(claims, references) {
|
|
127
|
+
const resourceType = detectClaimsResourceType(claims);
|
|
128
|
+
const claimKey = resourceType ? resolveContainedReferenceListClaimKey(resourceType) : undefined;
|
|
129
|
+
if (!claimKey || references.length === 0) {
|
|
130
|
+
return claims;
|
|
131
|
+
}
|
|
132
|
+
const current = splitCsv(claims[claimKey]);
|
|
133
|
+
const next = Array.from(new Set([...current, ...references].map((item) => asTrimmedString(item)).filter(Boolean)));
|
|
134
|
+
return {
|
|
135
|
+
...claims,
|
|
136
|
+
[claimKey]: next.join(','),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
96
139
|
export function detectClaimsResourceType(claims) {
|
|
97
140
|
const keys = Object.keys(claims || {});
|
|
98
141
|
if (keys.some((key) => key.startsWith('MedicationStatement.')))
|
|
@@ -181,12 +224,47 @@ export function extractBundleDocumentClaimsList(bundle, context = 'org.hl7.fhir.
|
|
|
181
224
|
.map((entry) => entry?.resource)
|
|
182
225
|
.filter((resource) => resource && typeof resource === 'object')
|
|
183
226
|
.filter((resource) => !ignoredResourceTypes.has(String(resource.resourceType || '')))
|
|
184
|
-
.
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
227
|
+
.flatMap((resource) => {
|
|
228
|
+
const resourceRecord = resource;
|
|
229
|
+
const resourceReference = `${asTrimmedString(resourceRecord.resourceType)}/${asTrimmedString(resourceRecord.id)}`;
|
|
230
|
+
const metaClaims = resourceRecord?.meta?.claims;
|
|
231
|
+
const baseClaims = metaClaims && typeof metaClaims === 'object' && !Array.isArray(metaClaims)
|
|
232
|
+
? ensureClaimsIdentifier({ ...metaClaims }, resourceRecord)
|
|
233
|
+
: ensureClaimsIdentifier(convertFhirResourceToClaims(resourceRecord, context), resourceRecord);
|
|
234
|
+
const containedResources = Array.isArray(resourceRecord.contained)
|
|
235
|
+
? resourceRecord.contained
|
|
236
|
+
: [];
|
|
237
|
+
const containedClaimsList = containedResources.map((containedResource, index) => {
|
|
238
|
+
const containedMetaClaims = (containedResource?.meta?.claims);
|
|
239
|
+
const containedClaims = containedMetaClaims && typeof containedMetaClaims === 'object' && !Array.isArray(containedMetaClaims)
|
|
240
|
+
? ensureClaimsIdentifier({ ...containedMetaClaims }, containedResource)
|
|
241
|
+
: ensureClaimsIdentifier(convertFhirResourceToClaims(containedResource, context), containedResource);
|
|
242
|
+
const containedResourceType = asTrimmedString(containedResource.resourceType);
|
|
243
|
+
const containedFlagClaimKey = resolveContainedFlagClaimKey(containedResourceType);
|
|
244
|
+
const containedParentReferenceClaimKey = resolveContainedParentReferenceClaimKey(containedResourceType);
|
|
245
|
+
return {
|
|
246
|
+
...containedClaims,
|
|
247
|
+
...(containedFlagClaimKey ? { [containedFlagClaimKey]: true } : {}),
|
|
248
|
+
...(containedParentReferenceClaimKey ? { [containedParentReferenceClaimKey]: resourceReference } : {}),
|
|
249
|
+
...(asTrimmedString(containedResource.id) ? {} : {
|
|
250
|
+
[`${containedResource.resourceType}.identifier`]: `${resourceReference}#contained-${index + 1}`,
|
|
251
|
+
}),
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
const containedReferences = containedResources
|
|
255
|
+
.map((containedResource, index) => {
|
|
256
|
+
const containedType = asTrimmedString(containedResource.resourceType);
|
|
257
|
+
const containedId = asTrimmedString(containedResource.id) || `${resourceReference}#contained-${index + 1}`;
|
|
258
|
+
if (!containedType || !containedId) {
|
|
259
|
+
return '';
|
|
260
|
+
}
|
|
261
|
+
return `${containedType}/${containedId}`;
|
|
262
|
+
})
|
|
263
|
+
.filter(Boolean);
|
|
264
|
+
return [
|
|
265
|
+
mergeContainedResourceReferenceList(baseClaims, containedReferences),
|
|
266
|
+
...containedClaimsList,
|
|
267
|
+
];
|
|
190
268
|
});
|
|
191
269
|
}
|
|
192
270
|
export function resolveClaimsSectionList(claims) {
|
|
@@ -202,9 +280,17 @@ export function resolveClaimsSectionList(claims) {
|
|
|
202
280
|
return Array.from(new Set(values));
|
|
203
281
|
}
|
|
204
282
|
export function buildBundleDocumentFromClaims(input) {
|
|
205
|
-
const
|
|
283
|
+
const compositionClaims = { ...(input.compositionClaims || {}) };
|
|
284
|
+
const compositionType = asTrimmedString(input.compositionType || compositionClaims[CompositionClaim.Type]) || 'http://loinc.org|60591-5';
|
|
285
|
+
const compositionSubject = asTrimmedString(input.subjectDid || compositionClaims[CompositionClaim.Subject]);
|
|
286
|
+
const compositionIdentifier = asTrimmedString(compositionClaims[CompositionClaim.Identifier]);
|
|
287
|
+
const compositionTitle = asTrimmedString(compositionClaims[CompositionClaim.Title]);
|
|
288
|
+
const compositionDate = asTrimmedString(compositionClaims[CompositionClaim.Date]);
|
|
289
|
+
const compositionAuthorList = splitCsv(compositionClaims[CompositionClaim.Author]);
|
|
206
290
|
const compositionSections = new Map();
|
|
207
|
-
const
|
|
291
|
+
const visibleEntries = [];
|
|
292
|
+
const resourceByReference = new Map();
|
|
293
|
+
const containedChildrenByParentReference = new Map();
|
|
208
294
|
input.claimsList.forEach((claims, index) => {
|
|
209
295
|
const resource = convertClaimsToFhirResource(claims);
|
|
210
296
|
resource.meta = {
|
|
@@ -212,8 +298,23 @@ export function buildBundleDocumentFromClaims(input) {
|
|
|
212
298
|
claims: { ...claims },
|
|
213
299
|
};
|
|
214
300
|
ensureResourceIdentifier(resource, claims, index);
|
|
215
|
-
|
|
216
|
-
const
|
|
301
|
+
const resourceReference = `${resource.resourceType}/${asTrimmedString(resource.id)}`;
|
|
302
|
+
const containedFlagClaimKey = resolveContainedFlagClaimKey(resource.resourceType);
|
|
303
|
+
const containedParentReferenceClaimKey = resolveContainedParentReferenceClaimKey(resource.resourceType);
|
|
304
|
+
const isContained = containedFlagClaimKey
|
|
305
|
+
? (claims[containedFlagClaimKey] === true || claims[containedFlagClaimKey] === 'true')
|
|
306
|
+
: false;
|
|
307
|
+
const containedParentReference = containedParentReferenceClaimKey
|
|
308
|
+
? asTrimmedString(claims[containedParentReferenceClaimKey])
|
|
309
|
+
: '';
|
|
310
|
+
if (isContained && containedParentReference) {
|
|
311
|
+
const currentChildren = containedChildrenByParentReference.get(containedParentReference) || [];
|
|
312
|
+
containedChildrenByParentReference.set(containedParentReference, [...currentChildren, resource]);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
visibleEntries.push({ resource });
|
|
316
|
+
resourceByReference.set(resourceReference, resource);
|
|
317
|
+
const resourceRef = resourceReference;
|
|
217
318
|
resolveClaimsSectionList(claims).forEach((sectionValue) => {
|
|
218
319
|
const normalizedSection = asTrimmedString(sectionValue);
|
|
219
320
|
if (!normalizedSection)
|
|
@@ -230,6 +331,13 @@ export function buildBundleDocumentFromClaims(input) {
|
|
|
230
331
|
compositionSections.set(normalizedSection, section);
|
|
231
332
|
});
|
|
232
333
|
});
|
|
334
|
+
containedChildrenByParentReference.forEach((children, parentReference) => {
|
|
335
|
+
const parent = resourceByReference.get(parentReference);
|
|
336
|
+
if (!parent) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
parent.contained = [...(Array.isArray(parent.contained) ? parent.contained : []), ...children];
|
|
340
|
+
});
|
|
233
341
|
const [compositionSystem, compositionCode] = compositionType.split('|');
|
|
234
342
|
return {
|
|
235
343
|
resourceType: ResourceTypesFhirR4.Bundle,
|
|
@@ -238,8 +346,14 @@ export function buildBundleDocumentFromClaims(input) {
|
|
|
238
346
|
{
|
|
239
347
|
resource: {
|
|
240
348
|
resourceType: ResourceTypesFhirR4.Composition,
|
|
349
|
+
...(compositionIdentifier ? { id: compositionIdentifier } : {}),
|
|
241
350
|
status: 'final',
|
|
242
|
-
|
|
351
|
+
...(compositionIdentifier ? {
|
|
352
|
+
identifier: [{ value: compositionIdentifier }],
|
|
353
|
+
} : {}),
|
|
354
|
+
...(compositionSubject ? {
|
|
355
|
+
subject: { reference: compositionSubject },
|
|
356
|
+
} : {}),
|
|
243
357
|
type: {
|
|
244
358
|
coding: [
|
|
245
359
|
compositionCode
|
|
@@ -247,18 +361,24 @@ export function buildBundleDocumentFromClaims(input) {
|
|
|
247
361
|
: { code: compositionSystem },
|
|
248
362
|
],
|
|
249
363
|
},
|
|
364
|
+
...(compositionTitle ? { title: compositionTitle } : {}),
|
|
365
|
+
...(compositionDate ? { date: compositionDate } : {}),
|
|
366
|
+
...(compositionAuthorList.length > 0 ? {
|
|
367
|
+
author: compositionAuthorList.map((reference) => ({ reference })),
|
|
368
|
+
} : {}),
|
|
369
|
+
meta: { claims: compositionClaims },
|
|
250
370
|
section: Array.from(compositionSections.values()),
|
|
251
371
|
},
|
|
252
372
|
},
|
|
253
|
-
...(
|
|
373
|
+
...(compositionSubject
|
|
254
374
|
? [{
|
|
255
375
|
resource: {
|
|
256
376
|
resourceType: 'Patient',
|
|
257
|
-
id:
|
|
377
|
+
id: compositionSubject,
|
|
258
378
|
},
|
|
259
379
|
}]
|
|
260
380
|
: []),
|
|
261
|
-
...
|
|
381
|
+
...visibleEntries,
|
|
262
382
|
],
|
|
263
383
|
};
|
|
264
384
|
}
|