@nexalink/carecompass-sdk 0.5.0 → 0.6.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/README.md CHANGED
@@ -185,6 +185,11 @@ field. The hosted runtime authorizes the workflow from the issued embed key and
185
185
  server-side tenant entitlement. Values in user context do not authorize a
186
186
  workflow.
187
187
 
188
+ Development and staging RCM requests must include `claimContext.stage` set to
189
+ the configured SDK environment (`"development"` or `"staging"`). Production
190
+ may omit the field. The hosted runtime validates any supplied value against the
191
+ authenticated key environment; this marker never grants workflow access.
192
+
188
193
  For the hosted RCM path, configure the tenant's RCM policy corpus in the
189
194
  CareCompass tenant portal before embedding: an authorized administrator must
190
195
  have an executed BAA, enable the RCM entitlement, set up the corpus, upload a
@@ -210,13 +215,11 @@ import {
210
215
  />;
211
216
  ```
212
217
 
213
- The included demo input is synthetic and contains no patient data. Use it only
214
- with synthetic, approved policy material during development. The package
215
- includes [`DEMO-ENC-1042-rcm-policy.md`](qa-fixtures/DEMO-ENC-1042-rcm-policy.md)
216
- for the matching demo. Upload that file through **RCM policy corpus**, give it
217
- the `2026.1-demo` version, explicitly approve it, and wait for ingestion before
218
- submitting `CARECOMPASS_RCM_SYNTHETIC_DEMO`. It is deliberately not a real payer
219
- policy or coding manual.
218
+ The included demo input is synthetic and contains no patient data. Its same-day
219
+ observation scenario is designed to retrieve the official CMS E/M evidence for
220
+ CPT 99236 from the Nexalink base corpus. Tenant policies may supplement the
221
+ base, but the runtime still requires an approved, active corpus and grounded
222
+ citations before returning a candidate.
220
223
 
221
224
  A production tenant must have an executed BAA, an RCM entitlement, and a
222
225
  healthy active corpus; otherwise the hosted workflow fails closed with a
package/dist/client.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { validateCareCompassConfig } from "./schema.js";
2
2
  import { CARECOMPASS_TELEMETRY_ERROR_CODES, CARECOMPASS_TELEMETRY_EVENTS, createCareCompassTelemetry, } from "./telemetry.js";
3
+ import { CARECOMPASS_SDK_VERSION } from "./version.js";
3
4
  // Internal error metadata keeps telemetry classification separate from messages,
4
5
  // which may include user-visible API details that should not be emitted.
5
6
  class CareCompassClientError extends Error {
@@ -185,6 +186,8 @@ export function createCareCompassClient(inputConfig, options = {}) {
185
186
  requestId: request.requestId,
186
187
  workflow: request.workflow,
187
188
  sessionId: request.sessionId,
189
+ sdkVersion: CARECOMPASS_SDK_VERSION,
190
+ applicationSurface: config.deploymentTarget,
188
191
  userContext: request.userContext,
189
192
  promptConfig: config.prompt,
190
193
  // Public routing preferences; the hosted runtime validates model
package/dist/rcm.d.ts CHANGED
@@ -10,6 +10,8 @@ export type RcmCodingAssistanceInput = {
10
10
  serviceDate?: string;
11
11
  placeOfService?: string;
12
12
  claimContext?: {
13
+ /** Required in development and staging; when supplied, it must match the authenticated SDK environment. */
14
+ stage?: CareCompassConfig["environment"];
13
15
  payerName?: string;
14
16
  submittedCodes?: string[];
15
17
  };
package/dist/rcm.js CHANGED
@@ -241,11 +241,15 @@ export function createRcmCodingWorkflow(config, options = {}) {
241
241
  }
242
242
  export const CARECOMPASS_RCM_SYNTHETIC_DEMO = {
243
243
  encounterId: "DEMO-ENC-1042",
244
- diagnosisNarrative: "Synthetic outpatient visit for persistent knee pain after activity.",
245
- procedureNarrative: "Synthetic clinician documentation describes a focused musculoskeletal evaluation.",
244
+ diagnosisNarrative: "Synthetic Medicare hospital observation encounter with same-day admission and discharge.",
245
+ procedureNarrative: "Synthetic clinician documented 110 minutes of qualifying same-day admission and discharge management time.",
246
246
  serviceDate: "2026-07-01",
247
- placeOfService: "11",
248
- claimContext: { payerName: "Demo Health Plan", submittedCodes: [] },
247
+ placeOfService: "22",
248
+ claimContext: {
249
+ stage: "development",
250
+ payerName: "Synthetic Medicare demo",
251
+ submittedCodes: ["99236"],
252
+ },
249
253
  };
250
254
  /** A small branded form suitable for embedding the pilot workflow in a host app. */
251
255
  export function RcmCodingAssistant({ config, initialInput = CARECOMPASS_RCM_SYNTHETIC_DEMO, onAuditEvent, onResult, onSafetyEvent, workflowOptions, }) {
@@ -1,4 +1,4 @@
1
- import type { CareCompassConfig } from "./schema.js";
1
+ import { type CareCompassConfig } from "./schema.js";
2
2
  export declare const CARECOMPASS_TELEMETRY_EVENTS: {
3
3
  readonly SDK_INITIALIZED: "carecompass_sdk_initialized";
4
4
  readonly SDK_INITIALIZATION_FAILED: "carecompass_sdk_initialization_failed";
@@ -98,11 +98,12 @@ export type CareCompassTelemetry = {
98
98
  captureAsync: (event: CareCompassTelemetryEvent, options?: CareCompassTelemetryCaptureOptions) => Promise<void>;
99
99
  };
100
100
  export declare const careCompassTelemetryDurationBucket: (durationMs: number) => CareCompassTelemetryDurationBucket;
101
- export declare function createCareCompassTelemetry(config: Pick<CareCompassConfig, "environment" | "payerId">, options?: {
101
+ export declare function createCareCompassTelemetry(config: Pick<CareCompassConfig, "apiBaseUrl" | "environment" | "payerId">, options?: {
102
102
  fetcher?: Fetcher;
103
103
  now?: () => Date;
104
104
  }): CareCompassTelemetry;
105
105
  export declare function createCareCompassCliTelemetry(sessionId: string, context?: {
106
+ apiBaseUrl?: string;
106
107
  environment?: CareCompassConfig["environment"];
107
108
  payerId?: string;
108
109
  }, options?: {
package/dist/telemetry.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { careCompassApiBaseUrlSchema, } from "./schema.js";
1
2
  import { CARECOMPASS_COMPONENT_VERSION, CARECOMPASS_SDK_VERSION, CARECOMPASS_TELEMETRY_CONTRACT_VERSION, } from "./version.js";
2
3
  export const CARECOMPASS_TELEMETRY_EVENTS = {
3
4
  SDK_INITIALIZED: "carecompass_sdk_initialized",
@@ -62,12 +63,9 @@ export const CARECOMPASS_TELEMETRY_ERROR_CODES = {
62
63
  CLI_COMMAND_UNKNOWN: "CLI_COMMAND_UNKNOWN",
63
64
  UNKNOWN_ERROR: "UNKNOWN_ERROR",
64
65
  };
65
- const POSTHOG_PROJECT_TOKEN_RE = /^phc_[A-Za-z0-9_-]{8,}$/;
66
- const POSTHOG_HOSTNAMES = new Set(["us.i.posthog.com", "eu.i.posthog.com"]);
67
- const CARECOMPASS_DEFAULT_POSTHOG_API_HOST = "https://us.i.posthog.com";
68
- const CARECOMPASS_DEFAULT_POSTHOG_PROJECT_TOKEN = "phc_vYl3rpIu6Iz5vCeJUG62BBA3nlPCeF4RSYpCb8FjnOl";
66
+ const CARECOMPASS_DEFAULT_API_BASE_URL = "https://www.nexalink.care";
67
+ const CARECOMPASS_TELEMETRY_PATH = "/api/carecompass/telemetry";
69
68
  const TELEMETRY_CAPTURE_TIMEOUT_MS = 1_000;
70
- const ANONYMOUS_DISTINCT_ID = "carecompass-sdk-anonymous";
71
69
  const TELEMETRY_EVENTS = new Set(Object.values(CARECOMPASS_TELEMETRY_EVENTS));
72
70
  const TELEMETRY_ERROR_CODES = new Set(Object.values(CARECOMPASS_TELEMETRY_ERROR_CODES));
73
71
  const FAILURE_CATEGORIES = new Set([
@@ -121,28 +119,15 @@ const disabledTelemetry = {
121
119
  capture: () => undefined,
122
120
  captureAsync: async () => undefined,
123
121
  };
124
- const approvedApiHost = (value, environment) => {
125
- // Telemetry is restricted to known PostHog ingestion hosts; localhost is only
126
- // accepted in development so tests and local captures can be isolated.
127
- if (typeof value !== "string")
122
+ const approvedRelayBaseUrl = (value, environment) => {
123
+ const parsed = careCompassApiBaseUrlSchema.safeParse(value);
124
+ if (!parsed.success)
128
125
  return null;
129
- try {
130
- const url = new URL(value);
131
- if (url.pathname !== "/" || url.search || url.hash)
132
- return null;
133
- const isLocalhost = url.hostname === "localhost" ||
134
- url.hostname === "127.0.0.1" ||
135
- url.hostname === "[::1]";
136
- if (isLocalhost) {
137
- return environment === "development" ? value.replace(/\/+$/, "") : null;
138
- }
139
- return url.protocol === "https:" && POSTHOG_HOSTNAMES.has(url.hostname)
140
- ? value.replace(/\/+$/, "")
141
- : null;
142
- }
143
- catch {
144
- return null;
145
- }
126
+ const url = new URL(parsed.data);
127
+ const isLocalhost = url.hostname === "localhost" ||
128
+ url.hostname === "127.0.0.1" ||
129
+ url.hostname === "[::1]";
130
+ return isLocalhost && environment !== "development" ? null : parsed.data;
146
131
  };
147
132
  export const careCompassTelemetryDurationBucket = (durationMs) => {
148
133
  if (durationMs < 250)
@@ -166,14 +151,10 @@ const allowedEnvironment = (value) => value === "development" || value === "stag
166
151
  ? value
167
152
  : "unknown";
168
153
  function createTelemetry(context, options = {}) {
169
- const projectToken = CARECOMPASS_DEFAULT_POSTHOG_PROJECT_TOKEN;
170
- if (!POSTHOG_PROJECT_TOKEN_RE.test(projectToken)) {
171
- return disabledTelemetry;
172
- }
173
154
  const fetcher = options.fetcher ?? fetch;
174
155
  const now = options.now ?? (() => new Date());
175
- const apiHost = approvedApiHost(CARECOMPASS_DEFAULT_POSTHOG_API_HOST, context.environment);
176
- if (!apiHost)
156
+ const relayBaseUrl = approvedRelayBaseUrl(context.apiBaseUrl, context.environment);
157
+ if (!relayBaseUrl)
177
158
  return disabledTelemetry;
178
159
  const captureAsync = async (event, captureOptions = {}) => {
179
160
  if (!TELEMETRY_EVENTS.has(event))
@@ -251,12 +232,10 @@ function createTelemetry(context, options = {}) {
251
232
  const controller = new AbortController();
252
233
  const timeout = setTimeout(() => controller.abort(), TELEMETRY_CAPTURE_TIMEOUT_MS);
253
234
  try {
254
- await fetcher(`${apiHost}/i/v0/e/`, {
235
+ await fetcher(`${relayBaseUrl}${CARECOMPASS_TELEMETRY_PATH}`, {
255
236
  method: "POST",
256
237
  headers: { "content-type": "application/json" },
257
238
  body: JSON.stringify({
258
- api_key: projectToken,
259
- distinct_id: ANONYMOUS_DISTINCT_ID,
260
239
  event,
261
240
  properties,
262
241
  timestamp: eventTimestamp,
@@ -279,6 +258,7 @@ function createTelemetry(context, options = {}) {
279
258
  }
280
259
  export function createCareCompassTelemetry(config, options = {}) {
281
260
  return createTelemetry({
261
+ apiBaseUrl: config.apiBaseUrl,
282
262
  environment: config.environment,
283
263
  platform: "web",
284
264
  }, options);
@@ -288,6 +268,7 @@ export function createCareCompassCliTelemetry(sessionId, context = {}, options =
288
268
  void sessionId;
289
269
  const environment = context.environment ?? "unknown";
290
270
  return createTelemetry({
271
+ apiBaseUrl: context.apiBaseUrl ?? CARECOMPASS_DEFAULT_API_BASE_URL,
291
272
  environment,
292
273
  platform: "cli",
293
274
  }, options);
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
- export const CARECOMPASS_SDK_VERSION = "0.5.0"; // x-release-please-version
1
+ export const CARECOMPASS_SDK_VERSION = "0.6.0"; // x-release-please-version
2
2
  export const CARECOMPASS_COMPONENT_VERSION = "1.0.0";
3
3
  export const CARECOMPASS_TELEMETRY_CONTRACT_VERSION = "1.1.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexalink/carecompass-sdk",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Embeddable CareCompass SDK and CLI for healthcare ecosystem integrations with Nexalink onboarding, BAA coverage, and API keys.",
5
5
  "type": "module",
6
6
  "packageManager": "bun@1.3.9",
@@ -74,8 +74,9 @@
74
74
  "tidy": "bun run lint && bun run format",
75
75
  "test": "NODE_OPTIONS=--experimental-vm-modules jest --runInBand --watchman=false",
76
76
  "audit": "bun audit",
77
- "release:check": "bun install --frozen-lockfile && bun run lint && bun run test && bun run build && bun run audit && bun run pack:dry-run",
78
- "pack:dry-run": "bun pm pack --dry-run --ignore-scripts"
77
+ "release:check": "bun install --frozen-lockfile && bun run lint && bun run test && bun run build && bun run audit && bun run verify:package-safety && bun run pack:dry-run",
78
+ "pack:dry-run": "bun pm pack --dry-run --ignore-scripts",
79
+ "verify:package-safety": "node scripts/verify-package-safety.mjs"
79
80
  },
80
81
  "dependencies": {
81
82
  "zod": "^4.4.3"
@@ -112,7 +113,7 @@
112
113
  "typescript-eslint": "^8.65.0"
113
114
  },
114
115
  "overrides": {
115
- "js-yaml": "4.3.0",
116
+ "js-yaml": "4.3.1",
116
117
  "minimatch": "10.2.5",
117
118
  "brace-expansion": "5.0.9"
118
119
  },