autoicd-js 0.3.0 → 0.4.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
@@ -96,7 +96,6 @@ const result = await autoicd.code(
96
96
  "Patient presents with acute bronchitis and chest pain",
97
97
  {
98
98
  topK: 3, // Top 3 ICD-10 candidates per entity (default: 5)
99
- strategy: "merged", // "individual" or "merged" entity strategy
100
99
  includeNegated: false, // Exclude negated conditions from results
101
100
  }
102
101
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autoicd-js",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "ICD-10 medical coding SDK — convert clinical text to ICD-10-CM diagnosis codes with AI-powered NLP. Automated medical coding, PHI de-identification, and ICD-10 code search for EHR, billing, and health-tech apps.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
package/dist/index.d.mts DELETED
@@ -1,224 +0,0 @@
1
- interface AutoICDOptions {
2
- /** API key (starts with `sk_`). */
3
- apiKey: string;
4
- /** Base URL. Defaults to `https://autoicdapi.com`. */
5
- baseURL?: string;
6
- /** Default timeout in milliseconds. Defaults to 30_000. */
7
- timeout?: number;
8
- /** Custom fetch implementation (for testing or non-standard runtimes). */
9
- fetch?: typeof globalThis.fetch;
10
- }
11
- interface CodeOptions {
12
- /** Number of top ICD-10 candidates per entity (1-25). Defaults to 5. */
13
- topK?: number;
14
- /** Include negated entities in results. Defaults to true. */
15
- includeNegated?: boolean;
16
- /** Matching strategy. Defaults to `"individual"`. */
17
- strategy?: "individual" | "merged";
18
- }
19
- interface CodeMatch {
20
- /** ICD-10-CM code (e.g., `"E11.21"`). */
21
- code: string;
22
- /** Official code description. */
23
- description: string;
24
- /** Cosine similarity score (0-1). */
25
- similarity: number;
26
- /** `"high"` if above high-confidence threshold, else `"moderate"`. */
27
- confidence: "high" | "moderate";
28
- /** The index term that produced this match. */
29
- matched_term: string;
30
- }
31
- interface CodingEntity {
32
- /** Entity text as extracted from the input. */
33
- entity_text: string;
34
- /** Character offset start in input text. */
35
- entity_start: number;
36
- /** Character offset end in input text. */
37
- entity_end: number;
38
- /** Whether this entity was negated in context. */
39
- negated: boolean;
40
- /** Entity refers to a past/resolved condition. */
41
- historical: boolean;
42
- /** Entity refers to a family member's condition. */
43
- family_history: boolean;
44
- /** Entity is hedged or uncertain. */
45
- uncertain: boolean;
46
- /** Severity modifier if detected (e.g., `"severe"`). */
47
- severity: string | null;
48
- /** Ranked ICD-10 code candidates. */
49
- codes: CodeMatch[];
50
- /** Source entity texts if this result was created by merging consecutive entities. */
51
- merged_from?: string[] | null;
52
- /** Original text before spell correction (null if no correction). */
53
- corrected_from?: string | null;
54
- }
55
- interface CodingResponse {
56
- /** The input text that was processed. */
57
- text: string;
58
- /** Coding provider used. */
59
- provider: string;
60
- /** Matching strategy used. */
61
- strategy: string;
62
- /** Total number of entities in results. */
63
- entity_count: number;
64
- /** Coding results per entity, sorted by position in text. */
65
- entities: CodingEntity[];
66
- }
67
- interface SearchOptions {
68
- /** Maximum number of results (1-100). Defaults to 20. */
69
- limit?: number;
70
- /** Number of results to skip (for pagination). Defaults to 0. */
71
- offset?: number;
72
- }
73
- interface CodeDetail {
74
- /** ICD-10-CM code. */
75
- code: string;
76
- /** Abbreviated description. */
77
- short_description: string;
78
- /** Full official description. */
79
- long_description: string;
80
- /** Whether this is a billable (leaf) code. */
81
- is_billable: boolean;
82
- }
83
- interface ChapterInfo {
84
- /** Chapter number (1-22). */
85
- number: number;
86
- /** Code range (e.g., `"E00-E89"`). */
87
- range: string;
88
- /** Chapter title. */
89
- title: string;
90
- }
91
- interface CodeDetailFull extends CodeDetail {
92
- /** Synonyms grouped by source: `"snomed"`, `"umls"`, `"icd10_augmented"`. */
93
- synonyms: Record<string, string[]>;
94
- /** Parent code in the ICD-10 hierarchy, or `null` for top-level categories. */
95
- parent: CodeDetail | null;
96
- /** Direct child codes in the ICD-10 hierarchy. */
97
- children: CodeDetail[];
98
- /** ICD-10-CM chapter this code belongs to. */
99
- chapter: ChapterInfo | null;
100
- /** Code block range (e.g., `"E08-E13"`). */
101
- block: string | null;
102
- }
103
- interface CodeSearchResponse {
104
- /** The search query that was used. */
105
- query: string;
106
- /** Number of results returned. */
107
- count: number;
108
- /** Matching ICD-10 codes. */
109
- codes: CodeDetail[];
110
- }
111
- interface PIIEntity {
112
- /** Original PII text. */
113
- text: string;
114
- /** Character offset start. */
115
- start: number;
116
- /** Character offset end. */
117
- end: number;
118
- /** PII category (NAME, DATE, SSN, PHONE, EMAIL, ADDRESS, MRN, AGE). */
119
- label: string;
120
- /** Replacement token (e.g., `"[NAME]"`). */
121
- replacement: string;
122
- }
123
- interface AnonymizeResponse {
124
- /** The input text that was processed. */
125
- original_text: string;
126
- /** Text with PII replaced by type labels. */
127
- anonymized_text: string;
128
- /** Number of PII entities detected. */
129
- pii_count: number;
130
- /** Detected PII spans with original offsets. */
131
- pii_entities: PIIEntity[];
132
- }
133
- interface RateLimit {
134
- /** Total requests allowed in the current period. */
135
- limit: number;
136
- /** Requests remaining. */
137
- remaining: number;
138
- /** UTC timestamp when the limit resets. */
139
- resetAt: Date;
140
- }
141
-
142
- declare class AutoICD {
143
- private readonly apiKey;
144
- private readonly baseURL;
145
- private readonly timeout;
146
- private readonly _fetch;
147
- /** Rate limit info from the most recent API response. */
148
- lastRateLimit: RateLimit | null;
149
- /** Sub-resource for ICD-10 code lookup. */
150
- readonly codes: Codes;
151
- constructor(options: AutoICDOptions);
152
- /**
153
- * Code clinical text to ICD-10-CM diagnoses.
154
- *
155
- * @example
156
- * ```ts
157
- * const result = await autoicd.code("Patient has type 2 diabetes");
158
- * for (const entity of result.entities) {
159
- * console.log(entity.entity_text, entity.codes[0]?.code);
160
- * }
161
- * ```
162
- */
163
- code(text: string, options?: CodeOptions): Promise<CodingResponse>;
164
- /**
165
- * Anonymize PHI/PII in clinical text.
166
- *
167
- * @example
168
- * ```ts
169
- * const result = await autoicd.anonymize("John Smith, DOB 01/15/1980, has COPD");
170
- * console.log(result.anonymized_text);
171
- * // "[NAME], DOB [DATE], has COPD"
172
- * ```
173
- */
174
- anonymize(text: string): Promise<AnonymizeResponse>;
175
- /** @internal */
176
- get<T>(path: string): Promise<T>;
177
- /** @internal */
178
- post<T>(path: string, body: Record<string, unknown>): Promise<T>;
179
- private request;
180
- }
181
- declare class Codes {
182
- private readonly client;
183
- constructor(client: AutoICD);
184
- /**
185
- * Search ICD-10 codes by description.
186
- *
187
- * @example
188
- * ```ts
189
- * const results = await autoicd.codes.search("diabetes mellitus");
190
- * ```
191
- */
192
- search(query: string, options?: SearchOptions): Promise<CodeSearchResponse>;
193
- /**
194
- * Get comprehensive details for a single ICD-10 code, including synonyms,
195
- * hierarchy (parent/children), chapter, and SNOMED CT / UMLS cross-references.
196
- *
197
- * @example
198
- * ```ts
199
- * const detail = await autoicd.codes.get("E11.9");
200
- * console.log(detail.long_description);
201
- * console.log(detail.synonyms.snomed); // SNOMED CT synonyms
202
- * console.log(detail.chapter?.title); // "Endocrine, Nutritional and Metabolic Diseases"
203
- * console.log(detail.children.length); // child codes
204
- * ```
205
- */
206
- get(code: string): Promise<CodeDetailFull>;
207
- }
208
-
209
- declare class AutoICDError extends Error {
210
- readonly status: number;
211
- constructor(status: number, message: string);
212
- }
213
- declare class AuthenticationError extends AutoICDError {
214
- constructor(message?: string);
215
- }
216
- declare class RateLimitError extends AutoICDError {
217
- readonly rateLimit: RateLimit;
218
- constructor(message: string, rateLimit: RateLimit);
219
- }
220
- declare class NotFoundError extends AutoICDError {
221
- constructor(message?: string);
222
- }
223
-
224
- export { type AnonymizeResponse, AuthenticationError, AutoICD, AutoICDError, type AutoICDOptions, type ChapterInfo, type CodeDetail, type CodeDetailFull, type CodeMatch, type CodeOptions, type CodeSearchResponse, type CodingEntity, type CodingResponse, NotFoundError, type PIIEntity, type RateLimit, RateLimitError, type SearchOptions };
package/dist/index.d.ts DELETED
@@ -1,224 +0,0 @@
1
- interface AutoICDOptions {
2
- /** API key (starts with `sk_`). */
3
- apiKey: string;
4
- /** Base URL. Defaults to `https://autoicdapi.com`. */
5
- baseURL?: string;
6
- /** Default timeout in milliseconds. Defaults to 30_000. */
7
- timeout?: number;
8
- /** Custom fetch implementation (for testing or non-standard runtimes). */
9
- fetch?: typeof globalThis.fetch;
10
- }
11
- interface CodeOptions {
12
- /** Number of top ICD-10 candidates per entity (1-25). Defaults to 5. */
13
- topK?: number;
14
- /** Include negated entities in results. Defaults to true. */
15
- includeNegated?: boolean;
16
- /** Matching strategy. Defaults to `"individual"`. */
17
- strategy?: "individual" | "merged";
18
- }
19
- interface CodeMatch {
20
- /** ICD-10-CM code (e.g., `"E11.21"`). */
21
- code: string;
22
- /** Official code description. */
23
- description: string;
24
- /** Cosine similarity score (0-1). */
25
- similarity: number;
26
- /** `"high"` if above high-confidence threshold, else `"moderate"`. */
27
- confidence: "high" | "moderate";
28
- /** The index term that produced this match. */
29
- matched_term: string;
30
- }
31
- interface CodingEntity {
32
- /** Entity text as extracted from the input. */
33
- entity_text: string;
34
- /** Character offset start in input text. */
35
- entity_start: number;
36
- /** Character offset end in input text. */
37
- entity_end: number;
38
- /** Whether this entity was negated in context. */
39
- negated: boolean;
40
- /** Entity refers to a past/resolved condition. */
41
- historical: boolean;
42
- /** Entity refers to a family member's condition. */
43
- family_history: boolean;
44
- /** Entity is hedged or uncertain. */
45
- uncertain: boolean;
46
- /** Severity modifier if detected (e.g., `"severe"`). */
47
- severity: string | null;
48
- /** Ranked ICD-10 code candidates. */
49
- codes: CodeMatch[];
50
- /** Source entity texts if this result was created by merging consecutive entities. */
51
- merged_from?: string[] | null;
52
- /** Original text before spell correction (null if no correction). */
53
- corrected_from?: string | null;
54
- }
55
- interface CodingResponse {
56
- /** The input text that was processed. */
57
- text: string;
58
- /** Coding provider used. */
59
- provider: string;
60
- /** Matching strategy used. */
61
- strategy: string;
62
- /** Total number of entities in results. */
63
- entity_count: number;
64
- /** Coding results per entity, sorted by position in text. */
65
- entities: CodingEntity[];
66
- }
67
- interface SearchOptions {
68
- /** Maximum number of results (1-100). Defaults to 20. */
69
- limit?: number;
70
- /** Number of results to skip (for pagination). Defaults to 0. */
71
- offset?: number;
72
- }
73
- interface CodeDetail {
74
- /** ICD-10-CM code. */
75
- code: string;
76
- /** Abbreviated description. */
77
- short_description: string;
78
- /** Full official description. */
79
- long_description: string;
80
- /** Whether this is a billable (leaf) code. */
81
- is_billable: boolean;
82
- }
83
- interface ChapterInfo {
84
- /** Chapter number (1-22). */
85
- number: number;
86
- /** Code range (e.g., `"E00-E89"`). */
87
- range: string;
88
- /** Chapter title. */
89
- title: string;
90
- }
91
- interface CodeDetailFull extends CodeDetail {
92
- /** Synonyms grouped by source: `"snomed"`, `"umls"`, `"icd10_augmented"`. */
93
- synonyms: Record<string, string[]>;
94
- /** Parent code in the ICD-10 hierarchy, or `null` for top-level categories. */
95
- parent: CodeDetail | null;
96
- /** Direct child codes in the ICD-10 hierarchy. */
97
- children: CodeDetail[];
98
- /** ICD-10-CM chapter this code belongs to. */
99
- chapter: ChapterInfo | null;
100
- /** Code block range (e.g., `"E08-E13"`). */
101
- block: string | null;
102
- }
103
- interface CodeSearchResponse {
104
- /** The search query that was used. */
105
- query: string;
106
- /** Number of results returned. */
107
- count: number;
108
- /** Matching ICD-10 codes. */
109
- codes: CodeDetail[];
110
- }
111
- interface PIIEntity {
112
- /** Original PII text. */
113
- text: string;
114
- /** Character offset start. */
115
- start: number;
116
- /** Character offset end. */
117
- end: number;
118
- /** PII category (NAME, DATE, SSN, PHONE, EMAIL, ADDRESS, MRN, AGE). */
119
- label: string;
120
- /** Replacement token (e.g., `"[NAME]"`). */
121
- replacement: string;
122
- }
123
- interface AnonymizeResponse {
124
- /** The input text that was processed. */
125
- original_text: string;
126
- /** Text with PII replaced by type labels. */
127
- anonymized_text: string;
128
- /** Number of PII entities detected. */
129
- pii_count: number;
130
- /** Detected PII spans with original offsets. */
131
- pii_entities: PIIEntity[];
132
- }
133
- interface RateLimit {
134
- /** Total requests allowed in the current period. */
135
- limit: number;
136
- /** Requests remaining. */
137
- remaining: number;
138
- /** UTC timestamp when the limit resets. */
139
- resetAt: Date;
140
- }
141
-
142
- declare class AutoICD {
143
- private readonly apiKey;
144
- private readonly baseURL;
145
- private readonly timeout;
146
- private readonly _fetch;
147
- /** Rate limit info from the most recent API response. */
148
- lastRateLimit: RateLimit | null;
149
- /** Sub-resource for ICD-10 code lookup. */
150
- readonly codes: Codes;
151
- constructor(options: AutoICDOptions);
152
- /**
153
- * Code clinical text to ICD-10-CM diagnoses.
154
- *
155
- * @example
156
- * ```ts
157
- * const result = await autoicd.code("Patient has type 2 diabetes");
158
- * for (const entity of result.entities) {
159
- * console.log(entity.entity_text, entity.codes[0]?.code);
160
- * }
161
- * ```
162
- */
163
- code(text: string, options?: CodeOptions): Promise<CodingResponse>;
164
- /**
165
- * Anonymize PHI/PII in clinical text.
166
- *
167
- * @example
168
- * ```ts
169
- * const result = await autoicd.anonymize("John Smith, DOB 01/15/1980, has COPD");
170
- * console.log(result.anonymized_text);
171
- * // "[NAME], DOB [DATE], has COPD"
172
- * ```
173
- */
174
- anonymize(text: string): Promise<AnonymizeResponse>;
175
- /** @internal */
176
- get<T>(path: string): Promise<T>;
177
- /** @internal */
178
- post<T>(path: string, body: Record<string, unknown>): Promise<T>;
179
- private request;
180
- }
181
- declare class Codes {
182
- private readonly client;
183
- constructor(client: AutoICD);
184
- /**
185
- * Search ICD-10 codes by description.
186
- *
187
- * @example
188
- * ```ts
189
- * const results = await autoicd.codes.search("diabetes mellitus");
190
- * ```
191
- */
192
- search(query: string, options?: SearchOptions): Promise<CodeSearchResponse>;
193
- /**
194
- * Get comprehensive details for a single ICD-10 code, including synonyms,
195
- * hierarchy (parent/children), chapter, and SNOMED CT / UMLS cross-references.
196
- *
197
- * @example
198
- * ```ts
199
- * const detail = await autoicd.codes.get("E11.9");
200
- * console.log(detail.long_description);
201
- * console.log(detail.synonyms.snomed); // SNOMED CT synonyms
202
- * console.log(detail.chapter?.title); // "Endocrine, Nutritional and Metabolic Diseases"
203
- * console.log(detail.children.length); // child codes
204
- * ```
205
- */
206
- get(code: string): Promise<CodeDetailFull>;
207
- }
208
-
209
- declare class AutoICDError extends Error {
210
- readonly status: number;
211
- constructor(status: number, message: string);
212
- }
213
- declare class AuthenticationError extends AutoICDError {
214
- constructor(message?: string);
215
- }
216
- declare class RateLimitError extends AutoICDError {
217
- readonly rateLimit: RateLimit;
218
- constructor(message: string, rateLimit: RateLimit);
219
- }
220
- declare class NotFoundError extends AutoICDError {
221
- constructor(message?: string);
222
- }
223
-
224
- export { type AnonymizeResponse, AuthenticationError, AutoICD, AutoICDError, type AutoICDOptions, type ChapterInfo, type CodeDetail, type CodeDetailFull, type CodeMatch, type CodeOptions, type CodeSearchResponse, type CodingEntity, type CodingResponse, NotFoundError, type PIIEntity, type RateLimit, RateLimitError, type SearchOptions };
package/dist/index.js DELETED
@@ -1,227 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- AuthenticationError: () => AuthenticationError,
24
- AutoICD: () => AutoICD,
25
- AutoICDError: () => AutoICDError,
26
- NotFoundError: () => NotFoundError,
27
- RateLimitError: () => RateLimitError
28
- });
29
- module.exports = __toCommonJS(index_exports);
30
-
31
- // src/errors.ts
32
- var AutoICDError = class extends Error {
33
- status;
34
- constructor(status, message) {
35
- super(message);
36
- this.name = "AutoICDError";
37
- this.status = status;
38
- }
39
- };
40
- var AuthenticationError = class extends AutoICDError {
41
- constructor(message = "Invalid API key") {
42
- super(401, message);
43
- this.name = "AuthenticationError";
44
- }
45
- };
46
- var RateLimitError = class extends AutoICDError {
47
- rateLimit;
48
- constructor(message, rateLimit) {
49
- super(429, message);
50
- this.name = "RateLimitError";
51
- this.rateLimit = rateLimit;
52
- }
53
- };
54
- var NotFoundError = class extends AutoICDError {
55
- constructor(message = "Resource not found") {
56
- super(404, message);
57
- this.name = "NotFoundError";
58
- }
59
- };
60
-
61
- // src/client.ts
62
- var DEFAULT_BASE_URL = "https://autoicdapi.com";
63
- var DEFAULT_TIMEOUT = 3e4;
64
- var AutoICD = class {
65
- apiKey;
66
- baseURL;
67
- timeout;
68
- _fetch;
69
- /** Rate limit info from the most recent API response. */
70
- lastRateLimit = null;
71
- /** Sub-resource for ICD-10 code lookup. */
72
- codes;
73
- constructor(options) {
74
- if (!options.apiKey) {
75
- throw new Error("apiKey is required");
76
- }
77
- this.apiKey = options.apiKey;
78
- this.baseURL = (options.baseURL ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
79
- this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
80
- this._fetch = options.fetch ?? globalThis.fetch;
81
- this.codes = new Codes(this);
82
- }
83
- // ─── Public Methods ───
84
- /**
85
- * Code clinical text to ICD-10-CM diagnoses.
86
- *
87
- * @example
88
- * ```ts
89
- * const result = await autoicd.code("Patient has type 2 diabetes");
90
- * for (const entity of result.entities) {
91
- * console.log(entity.entity_text, entity.codes[0]?.code);
92
- * }
93
- * ```
94
- */
95
- async code(text, options) {
96
- return this.post("/api/v1/code", {
97
- text,
98
- top_k: options?.topK,
99
- include_negated: options?.includeNegated,
100
- strategy: options?.strategy
101
- });
102
- }
103
- /**
104
- * Anonymize PHI/PII in clinical text.
105
- *
106
- * @example
107
- * ```ts
108
- * const result = await autoicd.anonymize("John Smith, DOB 01/15/1980, has COPD");
109
- * console.log(result.anonymized_text);
110
- * // "[NAME], DOB [DATE], has COPD"
111
- * ```
112
- */
113
- async anonymize(text) {
114
- return this.post("/api/v1/anonymize", { text });
115
- }
116
- // ─── Internal HTTP ───
117
- /** @internal */
118
- async get(path) {
119
- return this.request("GET", path);
120
- }
121
- /** @internal */
122
- async post(path, body) {
123
- const clean = Object.fromEntries(
124
- Object.entries(body).filter(([, v]) => v !== void 0)
125
- );
126
- return this.request("POST", path, clean);
127
- }
128
- async request(method, path, body) {
129
- const url = `${this.baseURL}${path}`;
130
- const controller = new AbortController();
131
- const timer = setTimeout(() => controller.abort(), this.timeout);
132
- try {
133
- const res = await this._fetch(url, {
134
- method,
135
- headers: {
136
- Authorization: `Bearer ${this.apiKey}`,
137
- "Content-Type": "application/json",
138
- Accept: "application/json"
139
- },
140
- body: body ? JSON.stringify(body) : void 0,
141
- signal: controller.signal
142
- });
143
- this.lastRateLimit = parseRateLimit(res.headers);
144
- if (res.ok) {
145
- return await res.json();
146
- }
147
- const errorBody = await res.json().catch(() => null);
148
- const message = errorBody?.error ?? `HTTP ${res.status}`;
149
- if (res.status === 401) throw new AuthenticationError(message);
150
- if (res.status === 404) throw new NotFoundError(message);
151
- if (res.status === 429) {
152
- throw new RateLimitError(
153
- message,
154
- this.lastRateLimit ?? {
155
- limit: errorBody?.limit ?? 0,
156
- remaining: 0,
157
- resetAt: errorBody?.resetAt ? new Date(errorBody.resetAt) : /* @__PURE__ */ new Date()
158
- }
159
- );
160
- }
161
- throw new AutoICDError(res.status, message);
162
- } catch (err) {
163
- if (err instanceof AutoICDError) throw err;
164
- if (err instanceof DOMException && err.name === "AbortError") {
165
- throw new AutoICDError(0, `Request timed out after ${this.timeout}ms`);
166
- }
167
- throw err;
168
- } finally {
169
- clearTimeout(timer);
170
- }
171
- }
172
- };
173
- var Codes = class {
174
- constructor(client) {
175
- this.client = client;
176
- }
177
- /**
178
- * Search ICD-10 codes by description.
179
- *
180
- * @example
181
- * ```ts
182
- * const results = await autoicd.codes.search("diabetes mellitus");
183
- * ```
184
- */
185
- async search(query, options) {
186
- const params = new URLSearchParams({ q: query });
187
- if (options?.limit !== void 0) params.set("limit", String(options.limit));
188
- if (options?.offset !== void 0) params.set("offset", String(options.offset));
189
- return this.client.get(`/api/v1/codes/search?${params}`);
190
- }
191
- /**
192
- * Get comprehensive details for a single ICD-10 code, including synonyms,
193
- * hierarchy (parent/children), chapter, and SNOMED CT / UMLS cross-references.
194
- *
195
- * @example
196
- * ```ts
197
- * const detail = await autoicd.codes.get("E11.9");
198
- * console.log(detail.long_description);
199
- * console.log(detail.synonyms.snomed); // SNOMED CT synonyms
200
- * console.log(detail.chapter?.title); // "Endocrine, Nutritional and Metabolic Diseases"
201
- * console.log(detail.children.length); // child codes
202
- * ```
203
- */
204
- async get(code) {
205
- return this.client.get(`/api/v1/codes/${encodeURIComponent(code)}`);
206
- }
207
- };
208
- function parseRateLimit(headers) {
209
- const limit = headers.get("X-RateLimit-Limit");
210
- const remaining = headers.get("X-RateLimit-Remaining");
211
- const reset = headers.get("X-RateLimit-Reset");
212
- if (!limit || !remaining || !reset) return null;
213
- return {
214
- limit: parseInt(limit, 10),
215
- remaining: parseInt(remaining, 10),
216
- resetAt: new Date(reset)
217
- };
218
- }
219
- // Annotate the CommonJS export names for ESM import in node:
220
- 0 && (module.exports = {
221
- AuthenticationError,
222
- AutoICD,
223
- AutoICDError,
224
- NotFoundError,
225
- RateLimitError
226
- });
227
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["export { AutoICD } from \"./client.js\";\n\nexport type {\n AutoICDOptions,\n CodeOptions,\n CodeMatch,\n CodingEntity,\n CodingResponse,\n SearchOptions,\n CodeDetail,\n CodeDetailFull,\n ChapterInfo,\n CodeSearchResponse,\n PIIEntity,\n AnonymizeResponse,\n RateLimit,\n} from \"./types.js\";\n\nexport {\n AutoICDError,\n AuthenticationError,\n RateLimitError,\n NotFoundError,\n} from \"./errors.js\";\n","import type { RateLimit } from \"./types.js\";\n\nexport class AutoICDError extends Error {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = \"AutoICDError\";\n this.status = status;\n }\n}\n\nexport class AuthenticationError extends AutoICDError {\n constructor(message = \"Invalid API key\") {\n super(401, message);\n this.name = \"AuthenticationError\";\n }\n}\n\nexport class RateLimitError extends AutoICDError {\n readonly rateLimit: RateLimit;\n\n constructor(message: string, rateLimit: RateLimit) {\n super(429, message);\n this.name = \"RateLimitError\";\n this.rateLimit = rateLimit;\n }\n}\n\nexport class NotFoundError extends AutoICDError {\n constructor(message = \"Resource not found\") {\n super(404, message);\n this.name = \"NotFoundError\";\n }\n}\n","import type {\n AutoICDOptions,\n CodeOptions,\n CodingResponse,\n SearchOptions,\n CodeSearchResponse,\n CodeDetail,\n CodeDetailFull,\n AnonymizeResponse,\n RateLimit,\n ErrorBody,\n} from \"./types.js\";\nimport {\n AutoICDError,\n AuthenticationError,\n RateLimitError,\n NotFoundError,\n} from \"./errors.js\";\n\nconst DEFAULT_BASE_URL = \"https://autoicdapi.com\";\nconst DEFAULT_TIMEOUT = 30_000;\n\nexport class AutoICD {\n private readonly apiKey: string;\n private readonly baseURL: string;\n private readonly timeout: number;\n private readonly _fetch: typeof globalThis.fetch;\n\n /** Rate limit info from the most recent API response. */\n lastRateLimit: RateLimit | null = null;\n\n /** Sub-resource for ICD-10 code lookup. */\n readonly codes: Codes;\n\n constructor(options: AutoICDOptions) {\n if (!options.apiKey) {\n throw new Error(\"apiKey is required\");\n }\n this.apiKey = options.apiKey;\n this.baseURL = (options.baseURL ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT;\n this._fetch = options.fetch ?? globalThis.fetch;\n this.codes = new Codes(this);\n }\n\n // ─── Public Methods ───\n\n /**\n * Code clinical text to ICD-10-CM diagnoses.\n *\n * @example\n * ```ts\n * const result = await autoicd.code(\"Patient has type 2 diabetes\");\n * for (const entity of result.entities) {\n * console.log(entity.entity_text, entity.codes[0]?.code);\n * }\n * ```\n */\n async code(text: string, options?: CodeOptions): Promise<CodingResponse> {\n return this.post<CodingResponse>(\"/api/v1/code\", {\n text,\n top_k: options?.topK,\n include_negated: options?.includeNegated,\n strategy: options?.strategy,\n });\n }\n\n /**\n * Anonymize PHI/PII in clinical text.\n *\n * @example\n * ```ts\n * const result = await autoicd.anonymize(\"John Smith, DOB 01/15/1980, has COPD\");\n * console.log(result.anonymized_text);\n * // \"[NAME], DOB [DATE], has COPD\"\n * ```\n */\n async anonymize(text: string): Promise<AnonymizeResponse> {\n return this.post<AnonymizeResponse>(\"/api/v1/anonymize\", { text });\n }\n\n // ─── Internal HTTP ───\n\n /** @internal */\n async get<T>(path: string): Promise<T> {\n return this.request<T>(\"GET\", path);\n }\n\n /** @internal */\n async post<T>(path: string, body: Record<string, unknown>): Promise<T> {\n // Strip undefined values so the API receives clean JSON\n const clean = Object.fromEntries(\n Object.entries(body).filter(([, v]) => v !== undefined)\n );\n return this.request<T>(\"POST\", path, clean);\n }\n\n private async request<T>(\n method: string,\n path: string,\n body?: Record<string, unknown>\n ): Promise<T> {\n const url = `${this.baseURL}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const res = await this._fetch(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n // Parse rate limit headers\n this.lastRateLimit = parseRateLimit(res.headers);\n\n if (res.ok) {\n return (await res.json()) as T;\n }\n\n // Error responses\n const errorBody = (await res.json().catch(() => null)) as ErrorBody | null;\n const message = errorBody?.error ?? `HTTP ${res.status}`;\n\n if (res.status === 401) throw new AuthenticationError(message);\n if (res.status === 404) throw new NotFoundError(message);\n if (res.status === 429) {\n throw new RateLimitError(\n message,\n this.lastRateLimit ?? {\n limit: errorBody?.limit ?? 0,\n remaining: 0,\n resetAt: errorBody?.resetAt ? new Date(errorBody.resetAt) : new Date(),\n }\n );\n }\n\n throw new AutoICDError(res.status, message);\n } catch (err) {\n if (err instanceof AutoICDError) throw err;\n if (err instanceof DOMException && err.name === \"AbortError\") {\n throw new AutoICDError(0, `Request timed out after ${this.timeout}ms`);\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\n// ─── Codes Sub-resource ───\n\nclass Codes {\n constructor(private readonly client: AutoICD) {}\n\n /**\n * Search ICD-10 codes by description.\n *\n * @example\n * ```ts\n * const results = await autoicd.codes.search(\"diabetes mellitus\");\n * ```\n */\n async search(query: string, options?: SearchOptions): Promise<CodeSearchResponse> {\n const params = new URLSearchParams({ q: query });\n if (options?.limit !== undefined) params.set(\"limit\", String(options.limit));\n if (options?.offset !== undefined) params.set(\"offset\", String(options.offset));\n return this.client.get<CodeSearchResponse>(`/api/v1/codes/search?${params}`);\n }\n\n /**\n * Get comprehensive details for a single ICD-10 code, including synonyms,\n * hierarchy (parent/children), chapter, and SNOMED CT / UMLS cross-references.\n *\n * @example\n * ```ts\n * const detail = await autoicd.codes.get(\"E11.9\");\n * console.log(detail.long_description);\n * console.log(detail.synonyms.snomed); // SNOMED CT synonyms\n * console.log(detail.chapter?.title); // \"Endocrine, Nutritional and Metabolic Diseases\"\n * console.log(detail.children.length); // child codes\n * ```\n */\n async get(code: string): Promise<CodeDetailFull> {\n return this.client.get<CodeDetailFull>(`/api/v1/codes/${encodeURIComponent(code)}`);\n }\n\n}\n\n// ─── Helpers ───\n\nfunction parseRateLimit(headers: Headers): RateLimit | null {\n const limit = headers.get(\"X-RateLimit-Limit\");\n const remaining = headers.get(\"X-RateLimit-Remaining\");\n const reset = headers.get(\"X-RateLimit-Reset\");\n\n if (!limit || !remaining || !reset) return null;\n\n return {\n limit: parseInt(limit, 10),\n remaining: parseInt(remaining, 10),\n resetAt: new Date(reset),\n };\n}\n"],"mappings":"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","names":[]}
package/dist/index.mjs DELETED
@@ -1,196 +0,0 @@
1
- // src/errors.ts
2
- var AutoICDError = class extends Error {
3
- status;
4
- constructor(status, message) {
5
- super(message);
6
- this.name = "AutoICDError";
7
- this.status = status;
8
- }
9
- };
10
- var AuthenticationError = class extends AutoICDError {
11
- constructor(message = "Invalid API key") {
12
- super(401, message);
13
- this.name = "AuthenticationError";
14
- }
15
- };
16
- var RateLimitError = class extends AutoICDError {
17
- rateLimit;
18
- constructor(message, rateLimit) {
19
- super(429, message);
20
- this.name = "RateLimitError";
21
- this.rateLimit = rateLimit;
22
- }
23
- };
24
- var NotFoundError = class extends AutoICDError {
25
- constructor(message = "Resource not found") {
26
- super(404, message);
27
- this.name = "NotFoundError";
28
- }
29
- };
30
-
31
- // src/client.ts
32
- var DEFAULT_BASE_URL = "https://autoicdapi.com";
33
- var DEFAULT_TIMEOUT = 3e4;
34
- var AutoICD = class {
35
- apiKey;
36
- baseURL;
37
- timeout;
38
- _fetch;
39
- /** Rate limit info from the most recent API response. */
40
- lastRateLimit = null;
41
- /** Sub-resource for ICD-10 code lookup. */
42
- codes;
43
- constructor(options) {
44
- if (!options.apiKey) {
45
- throw new Error("apiKey is required");
46
- }
47
- this.apiKey = options.apiKey;
48
- this.baseURL = (options.baseURL ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
49
- this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
50
- this._fetch = options.fetch ?? globalThis.fetch;
51
- this.codes = new Codes(this);
52
- }
53
- // ─── Public Methods ───
54
- /**
55
- * Code clinical text to ICD-10-CM diagnoses.
56
- *
57
- * @example
58
- * ```ts
59
- * const result = await autoicd.code("Patient has type 2 diabetes");
60
- * for (const entity of result.entities) {
61
- * console.log(entity.entity_text, entity.codes[0]?.code);
62
- * }
63
- * ```
64
- */
65
- async code(text, options) {
66
- return this.post("/api/v1/code", {
67
- text,
68
- top_k: options?.topK,
69
- include_negated: options?.includeNegated,
70
- strategy: options?.strategy
71
- });
72
- }
73
- /**
74
- * Anonymize PHI/PII in clinical text.
75
- *
76
- * @example
77
- * ```ts
78
- * const result = await autoicd.anonymize("John Smith, DOB 01/15/1980, has COPD");
79
- * console.log(result.anonymized_text);
80
- * // "[NAME], DOB [DATE], has COPD"
81
- * ```
82
- */
83
- async anonymize(text) {
84
- return this.post("/api/v1/anonymize", { text });
85
- }
86
- // ─── Internal HTTP ───
87
- /** @internal */
88
- async get(path) {
89
- return this.request("GET", path);
90
- }
91
- /** @internal */
92
- async post(path, body) {
93
- const clean = Object.fromEntries(
94
- Object.entries(body).filter(([, v]) => v !== void 0)
95
- );
96
- return this.request("POST", path, clean);
97
- }
98
- async request(method, path, body) {
99
- const url = `${this.baseURL}${path}`;
100
- const controller = new AbortController();
101
- const timer = setTimeout(() => controller.abort(), this.timeout);
102
- try {
103
- const res = await this._fetch(url, {
104
- method,
105
- headers: {
106
- Authorization: `Bearer ${this.apiKey}`,
107
- "Content-Type": "application/json",
108
- Accept: "application/json"
109
- },
110
- body: body ? JSON.stringify(body) : void 0,
111
- signal: controller.signal
112
- });
113
- this.lastRateLimit = parseRateLimit(res.headers);
114
- if (res.ok) {
115
- return await res.json();
116
- }
117
- const errorBody = await res.json().catch(() => null);
118
- const message = errorBody?.error ?? `HTTP ${res.status}`;
119
- if (res.status === 401) throw new AuthenticationError(message);
120
- if (res.status === 404) throw new NotFoundError(message);
121
- if (res.status === 429) {
122
- throw new RateLimitError(
123
- message,
124
- this.lastRateLimit ?? {
125
- limit: errorBody?.limit ?? 0,
126
- remaining: 0,
127
- resetAt: errorBody?.resetAt ? new Date(errorBody.resetAt) : /* @__PURE__ */ new Date()
128
- }
129
- );
130
- }
131
- throw new AutoICDError(res.status, message);
132
- } catch (err) {
133
- if (err instanceof AutoICDError) throw err;
134
- if (err instanceof DOMException && err.name === "AbortError") {
135
- throw new AutoICDError(0, `Request timed out after ${this.timeout}ms`);
136
- }
137
- throw err;
138
- } finally {
139
- clearTimeout(timer);
140
- }
141
- }
142
- };
143
- var Codes = class {
144
- constructor(client) {
145
- this.client = client;
146
- }
147
- /**
148
- * Search ICD-10 codes by description.
149
- *
150
- * @example
151
- * ```ts
152
- * const results = await autoicd.codes.search("diabetes mellitus");
153
- * ```
154
- */
155
- async search(query, options) {
156
- const params = new URLSearchParams({ q: query });
157
- if (options?.limit !== void 0) params.set("limit", String(options.limit));
158
- if (options?.offset !== void 0) params.set("offset", String(options.offset));
159
- return this.client.get(`/api/v1/codes/search?${params}`);
160
- }
161
- /**
162
- * Get comprehensive details for a single ICD-10 code, including synonyms,
163
- * hierarchy (parent/children), chapter, and SNOMED CT / UMLS cross-references.
164
- *
165
- * @example
166
- * ```ts
167
- * const detail = await autoicd.codes.get("E11.9");
168
- * console.log(detail.long_description);
169
- * console.log(detail.synonyms.snomed); // SNOMED CT synonyms
170
- * console.log(detail.chapter?.title); // "Endocrine, Nutritional and Metabolic Diseases"
171
- * console.log(detail.children.length); // child codes
172
- * ```
173
- */
174
- async get(code) {
175
- return this.client.get(`/api/v1/codes/${encodeURIComponent(code)}`);
176
- }
177
- };
178
- function parseRateLimit(headers) {
179
- const limit = headers.get("X-RateLimit-Limit");
180
- const remaining = headers.get("X-RateLimit-Remaining");
181
- const reset = headers.get("X-RateLimit-Reset");
182
- if (!limit || !remaining || !reset) return null;
183
- return {
184
- limit: parseInt(limit, 10),
185
- remaining: parseInt(remaining, 10),
186
- resetAt: new Date(reset)
187
- };
188
- }
189
- export {
190
- AuthenticationError,
191
- AutoICD,
192
- AutoICDError,
193
- NotFoundError,
194
- RateLimitError
195
- };
196
- //# sourceMappingURL=index.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/client.ts"],"sourcesContent":["import type { RateLimit } from \"./types.js\";\n\nexport class AutoICDError extends Error {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = \"AutoICDError\";\n this.status = status;\n }\n}\n\nexport class AuthenticationError extends AutoICDError {\n constructor(message = \"Invalid API key\") {\n super(401, message);\n this.name = \"AuthenticationError\";\n }\n}\n\nexport class RateLimitError extends AutoICDError {\n readonly rateLimit: RateLimit;\n\n constructor(message: string, rateLimit: RateLimit) {\n super(429, message);\n this.name = \"RateLimitError\";\n this.rateLimit = rateLimit;\n }\n}\n\nexport class NotFoundError extends AutoICDError {\n constructor(message = \"Resource not found\") {\n super(404, message);\n this.name = \"NotFoundError\";\n }\n}\n","import type {\n AutoICDOptions,\n CodeOptions,\n CodingResponse,\n SearchOptions,\n CodeSearchResponse,\n CodeDetail,\n CodeDetailFull,\n AnonymizeResponse,\n RateLimit,\n ErrorBody,\n} from \"./types.js\";\nimport {\n AutoICDError,\n AuthenticationError,\n RateLimitError,\n NotFoundError,\n} from \"./errors.js\";\n\nconst DEFAULT_BASE_URL = \"https://autoicdapi.com\";\nconst DEFAULT_TIMEOUT = 30_000;\n\nexport class AutoICD {\n private readonly apiKey: string;\n private readonly baseURL: string;\n private readonly timeout: number;\n private readonly _fetch: typeof globalThis.fetch;\n\n /** Rate limit info from the most recent API response. */\n lastRateLimit: RateLimit | null = null;\n\n /** Sub-resource for ICD-10 code lookup. */\n readonly codes: Codes;\n\n constructor(options: AutoICDOptions) {\n if (!options.apiKey) {\n throw new Error(\"apiKey is required\");\n }\n this.apiKey = options.apiKey;\n this.baseURL = (options.baseURL ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT;\n this._fetch = options.fetch ?? globalThis.fetch;\n this.codes = new Codes(this);\n }\n\n // ─── Public Methods ───\n\n /**\n * Code clinical text to ICD-10-CM diagnoses.\n *\n * @example\n * ```ts\n * const result = await autoicd.code(\"Patient has type 2 diabetes\");\n * for (const entity of result.entities) {\n * console.log(entity.entity_text, entity.codes[0]?.code);\n * }\n * ```\n */\n async code(text: string, options?: CodeOptions): Promise<CodingResponse> {\n return this.post<CodingResponse>(\"/api/v1/code\", {\n text,\n top_k: options?.topK,\n include_negated: options?.includeNegated,\n strategy: options?.strategy,\n });\n }\n\n /**\n * Anonymize PHI/PII in clinical text.\n *\n * @example\n * ```ts\n * const result = await autoicd.anonymize(\"John Smith, DOB 01/15/1980, has COPD\");\n * console.log(result.anonymized_text);\n * // \"[NAME], DOB [DATE], has COPD\"\n * ```\n */\n async anonymize(text: string): Promise<AnonymizeResponse> {\n return this.post<AnonymizeResponse>(\"/api/v1/anonymize\", { text });\n }\n\n // ─── Internal HTTP ───\n\n /** @internal */\n async get<T>(path: string): Promise<T> {\n return this.request<T>(\"GET\", path);\n }\n\n /** @internal */\n async post<T>(path: string, body: Record<string, unknown>): Promise<T> {\n // Strip undefined values so the API receives clean JSON\n const clean = Object.fromEntries(\n Object.entries(body).filter(([, v]) => v !== undefined)\n );\n return this.request<T>(\"POST\", path, clean);\n }\n\n private async request<T>(\n method: string,\n path: string,\n body?: Record<string, unknown>\n ): Promise<T> {\n const url = `${this.baseURL}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const res = await this._fetch(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n // Parse rate limit headers\n this.lastRateLimit = parseRateLimit(res.headers);\n\n if (res.ok) {\n return (await res.json()) as T;\n }\n\n // Error responses\n const errorBody = (await res.json().catch(() => null)) as ErrorBody | null;\n const message = errorBody?.error ?? `HTTP ${res.status}`;\n\n if (res.status === 401) throw new AuthenticationError(message);\n if (res.status === 404) throw new NotFoundError(message);\n if (res.status === 429) {\n throw new RateLimitError(\n message,\n this.lastRateLimit ?? {\n limit: errorBody?.limit ?? 0,\n remaining: 0,\n resetAt: errorBody?.resetAt ? new Date(errorBody.resetAt) : new Date(),\n }\n );\n }\n\n throw new AutoICDError(res.status, message);\n } catch (err) {\n if (err instanceof AutoICDError) throw err;\n if (err instanceof DOMException && err.name === \"AbortError\") {\n throw new AutoICDError(0, `Request timed out after ${this.timeout}ms`);\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\n// ─── Codes Sub-resource ───\n\nclass Codes {\n constructor(private readonly client: AutoICD) {}\n\n /**\n * Search ICD-10 codes by description.\n *\n * @example\n * ```ts\n * const results = await autoicd.codes.search(\"diabetes mellitus\");\n * ```\n */\n async search(query: string, options?: SearchOptions): Promise<CodeSearchResponse> {\n const params = new URLSearchParams({ q: query });\n if (options?.limit !== undefined) params.set(\"limit\", String(options.limit));\n if (options?.offset !== undefined) params.set(\"offset\", String(options.offset));\n return this.client.get<CodeSearchResponse>(`/api/v1/codes/search?${params}`);\n }\n\n /**\n * Get comprehensive details for a single ICD-10 code, including synonyms,\n * hierarchy (parent/children), chapter, and SNOMED CT / UMLS cross-references.\n *\n * @example\n * ```ts\n * const detail = await autoicd.codes.get(\"E11.9\");\n * console.log(detail.long_description);\n * console.log(detail.synonyms.snomed); // SNOMED CT synonyms\n * console.log(detail.chapter?.title); // \"Endocrine, Nutritional and Metabolic Diseases\"\n * console.log(detail.children.length); // child codes\n * ```\n */\n async get(code: string): Promise<CodeDetailFull> {\n return this.client.get<CodeDetailFull>(`/api/v1/codes/${encodeURIComponent(code)}`);\n }\n\n}\n\n// ─── Helpers ───\n\nfunction parseRateLimit(headers: Headers): RateLimit | null {\n const limit = headers.get(\"X-RateLimit-Limit\");\n const remaining = headers.get(\"X-RateLimit-Remaining\");\n const reset = headers.get(\"X-RateLimit-Reset\");\n\n if (!limit || !remaining || !reset) return null;\n\n return {\n limit: parseInt(limit, 10),\n remaining: parseInt(remaining, 10),\n resetAt: new Date(reset),\n };\n}\n"],"mappings":"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","names":[]}