@nexalink/carecompass-sdk 0.3.0-beta.15 → 0.5.0

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/dist/core.js ADDED
@@ -0,0 +1,352 @@
1
+ import { createCareCompassClient, } from "./client.js";
2
+ import { phiSummary, resolveCareCompassCompliancePolicy, sanitizeCareCompassValue, } from "./compliance.js";
3
+ const sleep = (durationMs) => new Promise((resolve) => setTimeout(resolve, durationMs));
4
+ const errorFrom = (error, code = "request_failed") => ({
5
+ code,
6
+ message: error instanceof Error ? error.message : String(error),
7
+ });
8
+ export function createCareCompassCore(config, options = {}) {
9
+ const now = options.now ?? Date.now;
10
+ const pollIntervalMs = options.pollIntervalMs ?? 1500;
11
+ const timeoutMs = options.timeoutMs ?? 120_000;
12
+ const client = createCareCompassClient(config, {
13
+ fetcher: options.fetcher,
14
+ now,
15
+ runtimeTokenProvider: options.runtimeTokenProvider,
16
+ });
17
+ const compliancePolicy = resolveCareCompassCompliancePolicy(config.compliance);
18
+ const auditEvents = [];
19
+ const auditListeners = new Set();
20
+ const safetyListeners = new Set();
21
+ if (options.onAuditEvent)
22
+ auditListeners.add(options.onAuditEvent);
23
+ if (options.onSafetyEvent)
24
+ safetyListeners.add(options.onSafetyEvent);
25
+ const listeners = new Set();
26
+ let sequence = 0;
27
+ let disposed = false;
28
+ let context = { ...(options.initialContext ?? {}) };
29
+ let phase = "idle";
30
+ let error = null;
31
+ let activeJobId = null;
32
+ let retry = null;
33
+ let messages = [
34
+ {
35
+ id: "welcome",
36
+ role: "assistant",
37
+ text: config.prompt.welcomeMessage,
38
+ createdAt: now(),
39
+ status: "complete",
40
+ },
41
+ ];
42
+ const nextId = (prefix) => `${prefix}-${now()}-${++sequence}`;
43
+ const emitAudit = (type, outcome, source, matches = []) => {
44
+ if (!compliancePolicy.auditEnabled)
45
+ return;
46
+ const auditEvent = {
47
+ id: nextId("audit"),
48
+ occurredAt: now(),
49
+ outcome,
50
+ phi: phiSummary(matches),
51
+ ...(source ? { source } : {}),
52
+ type,
53
+ };
54
+ auditEvents.push(auditEvent);
55
+ for (const listener of auditListeners)
56
+ listener(auditEvent);
57
+ };
58
+ const emitSafety = (decision, source, matches = []) => {
59
+ const safetyEvent = {
60
+ decision,
61
+ occurredAt: now(),
62
+ phi: phiSummary(matches),
63
+ source,
64
+ };
65
+ for (const listener of safetyListeners)
66
+ listener(safetyEvent);
67
+ emitAudit("safety_decision", decision === "policy_sensitive" ? "recorded" : decision, source, matches);
68
+ };
69
+ const applyPhiPolicy = (value, source) => {
70
+ const sanitized = sanitizeCareCompassValue(value, source, compliancePolicy, options.compliance?.phi);
71
+ if (sanitized.matches.length === 0)
72
+ return sanitized;
73
+ const decision = compliancePolicy.phiAction === "block"
74
+ ? "blocked"
75
+ : compliancePolicy.phiAction === "redact"
76
+ ? "redacted"
77
+ : "policy_sensitive";
78
+ emitSafety(decision, source, sanitized.matches);
79
+ return sanitized;
80
+ };
81
+ const getSnapshot = () => ({
82
+ messages: messages.map((message) => ({ ...message })),
83
+ phase,
84
+ loading: phase === "submitting" || phase === "streaming",
85
+ error: error ? { ...error } : null,
86
+ context: { ...context },
87
+ canRetry: !disposed && retry !== null && phase === "error",
88
+ retry: retry
89
+ ? {
90
+ prompt: retry.prompt,
91
+ requestId: retry.requestId,
92
+ workflow: retry.workflow,
93
+ context: { ...retry.context },
94
+ attempts: retry.attempts,
95
+ }
96
+ : null,
97
+ activeJobId,
98
+ });
99
+ const notify = () => {
100
+ const snapshot = getSnapshot();
101
+ for (const listener of listeners)
102
+ listener(snapshot);
103
+ };
104
+ const event = (value) => ({ ...value, snapshot: getSnapshot() });
105
+ const fail = (coreError) => {
106
+ error = coreError;
107
+ phase = disposed ? "disposed" : "error";
108
+ activeJobId = null;
109
+ emitAudit("error", "failed");
110
+ notify();
111
+ return event({ type: "error", error: coreError });
112
+ };
113
+ const ensureAvailable = () => {
114
+ if (!disposed)
115
+ return;
116
+ throw new Error("CareCompass core is disposed.");
117
+ };
118
+ async function* streamMessage(promptInput, sendOptions = {}) {
119
+ ensureAvailable();
120
+ if (phase === "submitting" || phase === "streaming") {
121
+ throw new Error("CareCompass request is already in progress.");
122
+ }
123
+ const prompt = promptInput.trim();
124
+ if (!prompt)
125
+ return;
126
+ const protectedPrompt = applyPhiPolicy(prompt, "message");
127
+ const protectedContext = applyPhiPolicy({
128
+ ...context,
129
+ ...(sendOptions.context ?? {}),
130
+ }, "context");
131
+ if (compliancePolicy.phiAction === "block" &&
132
+ (protectedPrompt.matches.length > 0 ||
133
+ protectedContext.matches.length > 0)) {
134
+ emitAudit("message", "blocked", "message", protectedPrompt.matches);
135
+ const blocked = {
136
+ code: "safety_blocked",
137
+ message: "CareCompass blocked this request because detectable PHI is not allowed in strict compliance mode.",
138
+ };
139
+ retry = null;
140
+ yield fail(blocked);
141
+ throw new Error(blocked.message);
142
+ }
143
+ const requestContext = protectedContext.value;
144
+ const protectedPromptValue = protectedPrompt.value;
145
+ const requestId = sendOptions.requestId ??
146
+ (typeof globalThis.crypto?.randomUUID === "function"
147
+ ? globalThis.crypto.randomUUID()
148
+ : nextId("request"));
149
+ const userMessage = {
150
+ id: nextId("user"),
151
+ role: "user",
152
+ text: protectedPromptValue,
153
+ createdAt: now(),
154
+ status: "complete",
155
+ };
156
+ messages = [...messages, userMessage];
157
+ phase = "submitting";
158
+ error = null;
159
+ activeJobId = null;
160
+ retry = null;
161
+ notify();
162
+ emitAudit("message", protectedPrompt.matches.length > 0 &&
163
+ compliancePolicy.phiAction === "redact"
164
+ ? "redacted"
165
+ : "submitted", "message", protectedPrompt.matches);
166
+ yield event({ type: "message_submitted", message: userMessage });
167
+ const startedAt = now();
168
+ let failureAlreadyCaptured = false;
169
+ try {
170
+ const { jobId } = await client.ask({
171
+ prompt: protectedPromptValue,
172
+ requestId,
173
+ workflow: sendOptions.workflow,
174
+ userContext: requestContext,
175
+ });
176
+ activeJobId = jobId;
177
+ phase = "streaming";
178
+ notify();
179
+ while (now() - startedAt < timeoutMs) {
180
+ const status = await client.status(jobId);
181
+ yield event({ type: "status", jobId, status: status.status });
182
+ if (status.status === "complete" && status.result) {
183
+ const protectedResponse = applyPhiPolicy(status.result, "response");
184
+ if (compliancePolicy.phiAction === "block" &&
185
+ protectedResponse.matches.length > 0) {
186
+ const blocked = {
187
+ code: "safety_blocked",
188
+ message: "CareCompass blocked a response because detectable PHI is not allowed in strict compliance mode.",
189
+ };
190
+ retry = null;
191
+ yield fail(blocked);
192
+ failureAlreadyCaptured = true;
193
+ throw new Error(blocked.message);
194
+ }
195
+ const assistantMessage = {
196
+ id: nextId("assistant"),
197
+ role: "assistant",
198
+ text: protectedResponse.value,
199
+ createdAt: now(),
200
+ status: "complete",
201
+ retrieval: status.retrieval,
202
+ };
203
+ messages = [...messages, assistantMessage];
204
+ phase = "complete";
205
+ error = null;
206
+ activeJobId = null;
207
+ retry = null;
208
+ notify();
209
+ emitAudit("message", protectedResponse.matches.length > 0 &&
210
+ compliancePolicy.phiAction === "redact"
211
+ ? "redacted"
212
+ : "completed", "response", protectedResponse.matches);
213
+ yield event({
214
+ type: "message_completed",
215
+ message: assistantMessage,
216
+ });
217
+ return;
218
+ }
219
+ if (status.status === "failed") {
220
+ const failed = errorFrom(new Error(status.result ?? config.labels.errorMessage));
221
+ retry = {
222
+ prompt: protectedPromptValue,
223
+ workflow: sendOptions.workflow,
224
+ context: requestContext,
225
+ attempts: 0,
226
+ };
227
+ yield fail(failed);
228
+ failureAlreadyCaptured = true;
229
+ throw new Error(failed.message);
230
+ }
231
+ if (pollIntervalMs > 0)
232
+ await sleep(pollIntervalMs);
233
+ }
234
+ client.recordInferenceTimeout(jobId, now() - startedAt);
235
+ const timedOut = errorFrom(new Error("CareCompass request timed out."), "timeout");
236
+ retry = {
237
+ prompt: protectedPromptValue,
238
+ requestId,
239
+ workflow: sendOptions.workflow,
240
+ context: requestContext,
241
+ attempts: 0,
242
+ };
243
+ yield fail(timedOut);
244
+ failureAlreadyCaptured = true;
245
+ throw new Error(timedOut.message);
246
+ }
247
+ catch (caught) {
248
+ if (failureAlreadyCaptured)
249
+ throw caught;
250
+ retry = {
251
+ prompt: protectedPromptValue,
252
+ requestId,
253
+ workflow: sendOptions.workflow,
254
+ context: requestContext,
255
+ attempts: 0,
256
+ };
257
+ const requestError = errorFrom(caught);
258
+ yield fail(requestError);
259
+ throw caught instanceof Error ? caught : new Error(requestError.message);
260
+ }
261
+ }
262
+ return {
263
+ exportAuditTrail: () => auditEvents.map((auditEvent) => ({
264
+ ...auditEvent,
265
+ phi: {
266
+ categories: [...auditEvent.phi.categories],
267
+ count: auditEvent.phi.count,
268
+ },
269
+ })),
270
+ getSnapshot,
271
+ recordSafetyDecision: (decision, source = "tool_call") => emitSafety(decision, source),
272
+ recordToolCall: (outcome = "completed") => emitAudit("tool_call", outcome, "tool_call"),
273
+ recordWidgetAction: (outcome = "recorded") => emitAudit("widget_action", outcome, "widget_action"),
274
+ subscribe: (listener) => {
275
+ listeners.add(listener);
276
+ return () => {
277
+ listeners.delete(listener);
278
+ };
279
+ },
280
+ subscribeAudit: (listener) => {
281
+ auditListeners.add(listener);
282
+ return () => auditListeners.delete(listener);
283
+ },
284
+ subscribeSafety: (listener) => {
285
+ safetyListeners.add(listener);
286
+ return () => safetyListeners.delete(listener);
287
+ },
288
+ setContext: (nextContext) => {
289
+ ensureAvailable();
290
+ context =
291
+ typeof nextContext === "function"
292
+ ? { ...nextContext({ ...context }) }
293
+ : { ...context, ...nextContext };
294
+ notify();
295
+ },
296
+ sendMessage: async (prompt, sendOptions) => {
297
+ const iterator = streamMessage(prompt, sendOptions)[Symbol.asyncIterator]();
298
+ while (!(await iterator.next()).done) {
299
+ // Consumers that only need the final state can use sendMessage.
300
+ }
301
+ return getSnapshot();
302
+ },
303
+ streamMessage,
304
+ retryLast: async () => {
305
+ ensureAvailable();
306
+ if (!retry)
307
+ return getSnapshot();
308
+ const retryRequest = retry;
309
+ retry = null;
310
+ return await streamRetry({
311
+ ...retryRequest,
312
+ attempts: retryRequest.attempts + 1,
313
+ });
314
+ },
315
+ reset: () => {
316
+ ensureAvailable();
317
+ messages = [
318
+ {
319
+ id: "welcome",
320
+ role: "assistant",
321
+ text: config.prompt.welcomeMessage,
322
+ createdAt: now(),
323
+ status: "complete",
324
+ },
325
+ ];
326
+ phase = "idle";
327
+ error = null;
328
+ activeJobId = null;
329
+ retry = null;
330
+ notify();
331
+ },
332
+ dispose: () => {
333
+ disposed = true;
334
+ phase = "disposed";
335
+ activeJobId = null;
336
+ listeners.clear();
337
+ auditListeners.clear();
338
+ safetyListeners.clear();
339
+ },
340
+ };
341
+ async function streamRetry(retryRequest) {
342
+ const iterator = streamMessage(retryRequest.prompt, {
343
+ requestId: retryRequest.requestId,
344
+ workflow: retryRequest.workflow,
345
+ context: retryRequest.context,
346
+ })[Symbol.asyncIterator]();
347
+ while (!(await iterator.next()).done) {
348
+ // Drain retry events.
349
+ }
350
+ return getSnapshot();
351
+ }
352
+ }
package/dist/index.d.ts CHANGED
@@ -1,10 +1,19 @@
1
1
  export { createCareCompassClient } from "./client.js";
2
- export type { CareCompassAskRequest, CareCompassAskResponse, CareCompassStatusResponse, } from "./client.js";
3
- export { CareCompassEmbed } from "./component.js";
2
+ export type { CareCompassAskRequest, CareCompassAskResponse, CareCompassClientOptions, CareCompassRetrievalMetadata, CareCompassRetrievalReference, CareCompassRuntimeTokenProvider, CareCompassRuntimeTokenRequest, CareCompassStatusResponse, CareCompassWorkflowId, } from "./client.js";
3
+ export { CareCompassChat, CareCompassEmbed, useCareCompass, } from "./component.js";
4
+ export type { CareCompassChatProps, CareCompassReactController, UseCareCompassOptions, } from "./component.js";
5
+ export { createCareCompassCore } from "./core.js";
6
+ export type { CareCompassContext, CareCompassCore, CareCompassCoreError, CareCompassCoreErrorCode, CareCompassCoreEvent, CareCompassCoreOptions, CareCompassCoreSnapshot, CareCompassLifecyclePhase, CareCompassMessage, CareCompassRetryMetadata, CareCompassSendMessageOptions, } from "./core.js";
7
+ export { CARECOMPASS_RCM_SYNTHETIC_DEMO, createRcmCodingWorkflow, RcmCodingAssistant, } from "./rcm.js";
8
+ export type { RcmCodeRecommendation, RcmCodeSystem, RcmCodingAssistanceInput, RcmCodingAssistanceResult, RcmCodingAssistantProps, RcmCodingWorkflow, RcmCodingWorkflowOptions, RcmConfidence, RcmCustomerRules, RcmPolicyReference, RcmPolicyRetriever, RcmReviewDisposition, } from "./rcm.js";
4
9
  export { mountCareCompass } from "./mount.js";
10
+ export { CARECOMPASS_ELEMENT_TAG, defineCareCompassElement, } from "./web-component.js";
11
+ export type { CareCompassWebComponentElement } from "./web-component.js";
5
12
  export { generateCareCompassIframeSnippet, generateCareCompassSnippet, } from "./snippet.js";
6
- export { careCompassApiBaseUrlSchema, careCompassConfigSchema, createDefaultCareCompassConfig, validateCareCompassConfig, } from "./schema.js";
7
- export type { CareCompassConfig, CareCompassConfigInput, CareCompassLabels, CareCompassPromptConfig, CareCompassTheme, CareCompassValidationResult, } from "./schema.js";
13
+ export { careCompassApiBaseUrlSchema, careCompassComplianceConfigSchema, careCompassConfigSchema, careCompassFeatureFlagsSchema, careCompassModelConfigSchema, createDefaultCareCompassConfig, validateCareCompassConfig, } from "./schema.js";
14
+ export type { CareCompassComplianceConfig, CareCompassConfig, CareCompassConfigInput, CareCompassFeatureFlags, CareCompassLabels, CareCompassModelConfig, CareCompassPromptConfig, CareCompassTheme, CareCompassValidationResult, } from "./schema.js";
15
+ export { CARECOMPASS_COMPLIANCE_PRESETS, detectCareCompassPhi, redactCareCompassPhi, resolveCareCompassCompliancePolicy, } from "./compliance.js";
16
+ export type { CareCompassAuditEvent, CareCompassAuditEventType, CareCompassAuditListener, CareCompassAuditOutcome, CareCompassAuditSource, CareCompassCompliancePolicy, CareCompassCompliancePreset, CareCompassComplianceRuntimeOptions, CareCompassPhiAction, CareCompassPhiCategory, CareCompassPhiDetectionContext, CareCompassPhiDetector, CareCompassPhiHooks, CareCompassPhiMatch, CareCompassPhiRedactor, CareCompassPhiSource, CareCompassSafetyDecision, CareCompassSafetyEvent, CareCompassSafetyListener, } from "./compliance.js";
8
17
  export { CARECOMPASS_TELEMETRY_ERROR_CODES, CARECOMPASS_TELEMETRY_EVENTS, careCompassTelemetryDurationBucket, createCareCompassCliTelemetry, createCareCompassTelemetry, } from "./telemetry.js";
9
18
  export type { CareCompassTelemetry, CareCompassTelemetryCaptureOptions, CareCompassTelemetryDurationBucket, CareCompassTelemetryErrorCode, CareCompassTelemetryEvent, CareCompassTelemetryFailureCategory, } from "./telemetry.js";
10
19
  export { CARECOMPASS_COMPONENT_VERSION, CARECOMPASS_SDK_VERSION, CARECOMPASS_TELEMETRY_CONTRACT_VERSION, } from "./version.js";
package/dist/index.js CHANGED
@@ -1,7 +1,11 @@
1
1
  export { createCareCompassClient } from "./client.js";
2
- export { CareCompassEmbed } from "./component.js";
2
+ export { CareCompassChat, CareCompassEmbed, useCareCompass, } from "./component.js";
3
+ export { createCareCompassCore } from "./core.js";
4
+ export { CARECOMPASS_RCM_SYNTHETIC_DEMO, createRcmCodingWorkflow, RcmCodingAssistant, } from "./rcm.js";
3
5
  export { mountCareCompass } from "./mount.js";
6
+ export { CARECOMPASS_ELEMENT_TAG, defineCareCompassElement, } from "./web-component.js";
4
7
  export { generateCareCompassIframeSnippet, generateCareCompassSnippet, } from "./snippet.js";
5
- export { careCompassApiBaseUrlSchema, careCompassConfigSchema, createDefaultCareCompassConfig, validateCareCompassConfig, } from "./schema.js";
8
+ export { careCompassApiBaseUrlSchema, careCompassComplianceConfigSchema, careCompassConfigSchema, careCompassFeatureFlagsSchema, careCompassModelConfigSchema, createDefaultCareCompassConfig, validateCareCompassConfig, } from "./schema.js";
9
+ export { CARECOMPASS_COMPLIANCE_PRESETS, detectCareCompassPhi, redactCareCompassPhi, resolveCareCompassCompliancePolicy, } from "./compliance.js";
6
10
  export { CARECOMPASS_TELEMETRY_ERROR_CODES, CARECOMPASS_TELEMETRY_EVENTS, careCompassTelemetryDurationBucket, createCareCompassCliTelemetry, createCareCompassTelemetry, } from "./telemetry.js";
7
11
  export { CARECOMPASS_COMPONENT_VERSION, CARECOMPASS_SDK_VERSION, CARECOMPASS_TELEMETRY_CONTRACT_VERSION, } from "./version.js";
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ export declare function CareCompassMarkdown({ text }: {
3
+ text: string;
4
+ }): React.JSX.Element;
@@ -0,0 +1,183 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from "react";
3
+ const markdownContainerStyle = {
4
+ alignItems: "stretch",
5
+ display: "flex",
6
+ flexDirection: "column",
7
+ gap: 10,
8
+ inlineSize: "100%",
9
+ lineHeight: 1.55,
10
+ textAlign: "start",
11
+ };
12
+ const compactBlockStyle = {
13
+ marginBlock: 0,
14
+ textAlign: "start",
15
+ };
16
+ const listStyle = {
17
+ display: "flex",
18
+ flexDirection: "column",
19
+ gap: 6,
20
+ marginBlock: 0,
21
+ paddingInlineStart: 22,
22
+ textAlign: "start",
23
+ };
24
+ const nestedListStyle = {
25
+ ...listStyle,
26
+ gap: 4,
27
+ marginBlockStart: 6,
28
+ };
29
+ const listItemStyle = {
30
+ paddingInlineStart: 2,
31
+ textAlign: "start",
32
+ };
33
+ const tableWrapStyle = {
34
+ marginBlock: 2,
35
+ overflowX: "auto",
36
+ textAlign: "start",
37
+ };
38
+ const tableStyle = {
39
+ borderCollapse: "collapse",
40
+ fontSize: "0.92em",
41
+ inlineSize: "100%",
42
+ textAlign: "start",
43
+ };
44
+ const cellStyle = {
45
+ border: "1px solid color-mix(in srgb, currentColor 18%, transparent)",
46
+ padding: "7px 9px",
47
+ textAlign: "start",
48
+ verticalAlign: "top",
49
+ };
50
+ const isTableSeparator = (line) => /^\s*\|?\s*:?-{3,}:?\s*(?:\|\s*:?-{3,}:?\s*)+\|?\s*$/.test(line);
51
+ const isTableRow = (line) => line.includes("|");
52
+ const splitTableRow = (line) => line
53
+ .trim()
54
+ .replace(/^\|/, "")
55
+ .replace(/\|$/, "")
56
+ .split("|")
57
+ .map((cell) => cell.trim());
58
+ const isBlockStart = (line, nextLine) => /^#{1,6}\s+/.test(line) ||
59
+ /^\s*[-*]\s+/.test(line) ||
60
+ /^\s*\d+\.\s+/.test(line) ||
61
+ line.trim() === "---" ||
62
+ (isTableRow(line) && nextLine !== undefined && isTableSeparator(nextLine));
63
+ function renderInline(text, keyPrefix) {
64
+ const parts = [];
65
+ const pattern = /\*\*([^*]+)\*\*/g;
66
+ let lastIndex = 0;
67
+ let match;
68
+ while ((match = pattern.exec(text)) !== null) {
69
+ if (match.index > lastIndex) {
70
+ parts.push(text.slice(lastIndex, match.index));
71
+ }
72
+ parts.push(_jsx("strong", { style: { fontWeight: 700 }, children: match[1] }, `${keyPrefix}-strong-${match.index}`));
73
+ lastIndex = match.index + match[0].length;
74
+ }
75
+ if (lastIndex < text.length) {
76
+ parts.push(text.slice(lastIndex));
77
+ }
78
+ return parts.length ? parts : text;
79
+ }
80
+ export function CareCompassMarkdown({ text }) {
81
+ const lines = text.replace(/\r\n/g, "\n").split("\n");
82
+ const blocks = [];
83
+ for (let index = 0; index < lines.length; index += 1) {
84
+ const line = lines[index];
85
+ const trimmed = line.trim();
86
+ if (!trimmed)
87
+ continue;
88
+ const heading = /^(#{1,6})\s+(.+)$/.exec(trimmed);
89
+ if (heading) {
90
+ const level = Math.min(heading[1].length, 6);
91
+ const tag = `h${level}`;
92
+ blocks.push(React.createElement(tag, {
93
+ key: `heading-${index}`,
94
+ style: {
95
+ fontSize: level <= 3 ? "1.05em" : "0.98em",
96
+ fontWeight: 700,
97
+ lineHeight: 1.25,
98
+ marginBlock: "2px 0",
99
+ textAlign: "start",
100
+ },
101
+ }, renderInline(heading[2], `heading-${index}`)));
102
+ continue;
103
+ }
104
+ if (trimmed === "---") {
105
+ blocks.push(_jsx("hr", { style: {
106
+ border: 0,
107
+ borderBlockStart: "1px solid color-mix(in srgb, currentColor 18%, transparent)",
108
+ inlineSize: "100%",
109
+ marginBlock: 4,
110
+ } }, `hr-${index}`));
111
+ continue;
112
+ }
113
+ if (isTableRow(trimmed) &&
114
+ lines[index + 1] !== undefined &&
115
+ isTableSeparator(lines[index + 1])) {
116
+ const headers = splitTableRow(trimmed);
117
+ const rows = [];
118
+ index += 2;
119
+ while (index < lines.length && isTableRow(lines[index].trim())) {
120
+ rows.push(splitTableRow(lines[index]));
121
+ index += 1;
122
+ }
123
+ index -= 1;
124
+ blocks.push(_jsx("div", { style: tableWrapStyle, children: _jsxs("table", { style: tableStyle, children: [_jsx("thead", { children: _jsx("tr", { children: headers.map((header, headerIndex) => (_jsx("th", { scope: "col", style: { ...cellStyle, fontWeight: 700 }, children: renderInline(header, `header-${index}-${headerIndex}`) }, `header-${headerIndex}`))) }) }), _jsx("tbody", { children: rows.map((row, rowIndex) => (_jsx("tr", { children: headers.map((_, cellIndex) => (_jsx("td", { style: cellStyle, children: renderInline(row[cellIndex] ?? "", `cell-${index}-${rowIndex}-${cellIndex}`) }, `cell-${cellIndex}`))) }, `row-${rowIndex}`))) })] }) }, `table-wrap-${index}`));
125
+ continue;
126
+ }
127
+ if (/^\s*[-*]\s+/.test(line)) {
128
+ const items = [];
129
+ while (index < lines.length && /^\s*[-*]\s+/.test(lines[index])) {
130
+ items.push(lines[index].replace(/^\s*[-*]\s+/, ""));
131
+ index += 1;
132
+ }
133
+ index -= 1;
134
+ blocks.push(_jsx("ul", { style: listStyle, children: items.map((item, itemIndex) => (_jsx("li", { style: listItemStyle, children: renderInline(item, `ul-${index}-${itemIndex}`) }, `li-${itemIndex}`))) }, `ul-${index}`));
135
+ continue;
136
+ }
137
+ if (/^\s*\d+\.\s+/.test(line)) {
138
+ const items = [];
139
+ while (index < lines.length) {
140
+ const orderedMatch = /^\s*\d+\.\s+(.+)$/.exec(lines[index]);
141
+ if (!orderedMatch)
142
+ break;
143
+ const item = {
144
+ text: orderedMatch[1],
145
+ bullets: [],
146
+ };
147
+ index += 1;
148
+ while (index < lines.length) {
149
+ const next = lines[index];
150
+ const nextTrimmed = next.trim();
151
+ if (!nextTrimmed) {
152
+ index += 1;
153
+ continue;
154
+ }
155
+ if (/^\s*[-*]\s+/.test(next)) {
156
+ item.bullets.push(next.replace(/^\s*[-*]\s+/, ""));
157
+ index += 1;
158
+ continue;
159
+ }
160
+ if (/^\s*\d+\.\s+/.test(next))
161
+ break;
162
+ if (isBlockStart(nextTrimmed, lines[index + 1]))
163
+ break;
164
+ item.bullets.push(nextTrimmed);
165
+ index += 1;
166
+ }
167
+ items.push(item);
168
+ }
169
+ index -= 1;
170
+ blocks.push(_jsx("ol", { style: listStyle, children: items.map((item, itemIndex) => (_jsxs("li", { style: listItemStyle, children: [renderInline(item.text, `ol-${index}-${itemIndex}`), item.bullets.length ? (_jsx("ul", { style: nestedListStyle, children: item.bullets.map((bullet, bulletIndex) => (_jsx("li", { style: listItemStyle, children: renderInline(bullet, `ol-${index}-${itemIndex}-${bulletIndex}`) }, `bullet-${bulletIndex}`))) })) : null] }, `li-${itemIndex}`))) }, `ol-${index}`));
171
+ continue;
172
+ }
173
+ const paragraphLines = [trimmed];
174
+ while (index + 1 < lines.length &&
175
+ lines[index + 1].trim() &&
176
+ !isBlockStart(lines[index + 1].trim(), lines[index + 2])) {
177
+ index += 1;
178
+ paragraphLines.push(lines[index].trim());
179
+ }
180
+ blocks.push(_jsx("p", { style: compactBlockStyle, children: renderInline(paragraphLines.join(" "), `p-${index}`) }, `p-${index}`));
181
+ }
182
+ return _jsx("div", { style: markdownContainerStyle, children: blocks });
183
+ }
package/dist/mount.d.ts CHANGED
@@ -1,4 +1,7 @@
1
+ import type { CareCompassRuntimeTokenProvider } from "./client.js";
1
2
  import type { CareCompassConfig } from "./schema.js";
2
- export declare function mountCareCompass(element: Element | null, config: CareCompassConfig): {
3
+ export declare function mountCareCompass(element: Element | null, config: CareCompassConfig, options?: {
4
+ runtimeTokenProvider?: CareCompassRuntimeTokenProvider;
5
+ }): {
3
6
  unmount: () => void;
4
7
  };
package/dist/mount.js CHANGED
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createRoot } from "react-dom/client";
3
3
  import { CareCompassEmbed } from "./component.js";
4
4
  import { CARECOMPASS_TELEMETRY_ERROR_CODES, CARECOMPASS_TELEMETRY_EVENTS, createCareCompassTelemetry, } from "./telemetry.js";
5
- export function mountCareCompass(element, config) {
5
+ export function mountCareCompass(element, config, options = {}) {
6
6
  if (!element) {
7
7
  // Missing mount points usually mean a copied snippet and page markup drifted
8
8
  // apart, so capture the setup error before throwing to the caller.
@@ -13,7 +13,7 @@ export function mountCareCompass(element, config) {
13
13
  throw new Error("CareCompass mount element was not found.");
14
14
  }
15
15
  const root = createRoot(element);
16
- root.render(_jsx(CareCompassEmbed, { config: config }));
16
+ root.render(_jsx(CareCompassEmbed, { config: config, runtimeTokenProvider: options.runtimeTokenProvider }));
17
17
  return {
18
18
  // Return the small React root facade so non-React hosts can clean up embeds.
19
19
  unmount: () => root.unmount(),