highflame 0.2.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/index.js ADDED
@@ -0,0 +1,666 @@
1
+ // src/errors.ts
2
+ var HighflameError = class extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "HighflameError";
6
+ }
7
+ };
8
+ var APIError = class extends HighflameError {
9
+ constructor(status, title, detail) {
10
+ super(`[${status}] ${title}: ${detail}`);
11
+ this.status = status;
12
+ this.title = title;
13
+ this.detail = detail;
14
+ this.name = "APIError";
15
+ }
16
+ };
17
+ var AuthenticationError = class extends APIError {
18
+ constructor(detail = "Invalid or expired credentials") {
19
+ super(401, "Unauthorized", detail);
20
+ this.name = "AuthenticationError";
21
+ }
22
+ };
23
+ var RateLimitError = class extends APIError {
24
+ constructor(detail = "Rate limit exceeded") {
25
+ super(429, "Too Many Requests", detail);
26
+ this.name = "RateLimitError";
27
+ }
28
+ };
29
+ var APIConnectionError = class extends HighflameError {
30
+ constructor(message) {
31
+ super(message);
32
+ this.name = "APIConnectionError";
33
+ }
34
+ };
35
+ var BlockedError = class extends HighflameError {
36
+ constructor(response) {
37
+ super(`Blocked by guard: ${response.policy_reason || response.decision}`);
38
+ this.response = response;
39
+ this.name = "BlockedError";
40
+ }
41
+ };
42
+
43
+ // src/stream.ts
44
+ function* parseSseLines(lines) {
45
+ let event = "detector_result";
46
+ let data = "";
47
+ for (const line of lines) {
48
+ if (line === "") {
49
+ if (data) {
50
+ yield { event, data };
51
+ }
52
+ event = "detector_result";
53
+ data = "";
54
+ } else if (line.startsWith("event:")) {
55
+ event = line.slice(6).trim();
56
+ } else if (line.startsWith("data:")) {
57
+ data = line.slice(5).trim();
58
+ }
59
+ }
60
+ if (data) {
61
+ yield { event, data };
62
+ }
63
+ }
64
+ async function* streamSseResponse(response) {
65
+ if (!response.body) {
66
+ throw new APIConnectionError("Response body is null");
67
+ }
68
+ const reader = response.body.getReader();
69
+ const decoder = new TextDecoder();
70
+ let buffer = "";
71
+ try {
72
+ while (true) {
73
+ const { done, value } = await reader.read();
74
+ if (done) break;
75
+ buffer += decoder.decode(value, { stream: true });
76
+ const lines = buffer.split("\n");
77
+ buffer = lines.pop() ?? "";
78
+ for (const { event, data } of parseSseLines(lines)) {
79
+ if (!data) continue;
80
+ let parsed;
81
+ try {
82
+ parsed = JSON.parse(data);
83
+ } catch {
84
+ continue;
85
+ }
86
+ yield {
87
+ type: event,
88
+ data: parsed
89
+ };
90
+ }
91
+ }
92
+ if (buffer) {
93
+ const lines = buffer.split("\n");
94
+ for (const { event, data } of parseSseLines([...lines, ""])) {
95
+ if (!data) continue;
96
+ let parsed;
97
+ try {
98
+ parsed = JSON.parse(data);
99
+ } catch {
100
+ continue;
101
+ }
102
+ yield {
103
+ type: event,
104
+ data: parsed
105
+ };
106
+ }
107
+ }
108
+ } finally {
109
+ reader.releaseLock();
110
+ }
111
+ }
112
+
113
+ // src/client.ts
114
+ var VERSION = "0.2.0";
115
+ var DEFAULT_TIMEOUT_MS = 3e4;
116
+ var DEFAULT_MAX_RETRIES = 2;
117
+ var RETRY_STATUS_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
118
+ var TOKEN_REFRESH_BUFFER_MS = 6e4;
119
+ var USER_AGENT = `highflame-js/${VERSION}`;
120
+ var SAAS_BASE_URL = "https://shield.api.highflame.ai";
121
+ var SAAS_TOKEN_URL = "https://studio.api.highflame.ai/api/cli-auth/token";
122
+ var LOG_BODY_MAX = 1024;
123
+ var NOOP_LOGGER = {
124
+ debug() {
125
+ },
126
+ info() {
127
+ },
128
+ warn() {
129
+ }
130
+ };
131
+ function truncate(text, max = LOG_BODY_MAX) {
132
+ if (text.length <= max) return text;
133
+ return text.slice(0, max) + `... (${text.length} chars)`;
134
+ }
135
+ function sleep(ms) {
136
+ return new Promise((resolve) => setTimeout(resolve, ms));
137
+ }
138
+ function retryDelay(attempt) {
139
+ const base = 1e3 * Math.pow(2, attempt);
140
+ const jitter = base * 0.25 * (2 * Math.random() - 1);
141
+ return Math.max(0, base + jitter);
142
+ }
143
+ async function parseError(response) {
144
+ let title = response.statusText || "Error";
145
+ let detail = "";
146
+ try {
147
+ const body = await response.json();
148
+ if (typeof body["title"] === "string") title = body["title"];
149
+ if (typeof body["detail"] === "string") detail = body["detail"];
150
+ } catch {
151
+ try {
152
+ detail = await response.text();
153
+ } catch {
154
+ }
155
+ }
156
+ if (response.status === 401) return new AuthenticationError(detail);
157
+ if (response.status === 429) return new RateLimitError(detail);
158
+ return new APIError(response.status, title, detail);
159
+ }
160
+ var GuardResource = class {
161
+ constructor(_client) {
162
+ this._client = _client;
163
+ }
164
+ /** Evaluate content against guard policies (POST /v1/guard). */
165
+ async evaluate(request, options) {
166
+ return this._client._postJSON("/v1/guard", request, options?.timeout);
167
+ }
168
+ /** Shorthand: evaluate a user prompt. */
169
+ async evaluatePrompt(content, options) {
170
+ const { timeout, ...rest } = options ?? {};
171
+ return this.evaluate(
172
+ { content, content_type: "prompt", action: "process_prompt", ...rest },
173
+ { timeout }
174
+ );
175
+ }
176
+ /** Shorthand: evaluate a tool call. */
177
+ async evaluateToolCall(toolName, args, options) {
178
+ const { timeout, ...rest } = options ?? {};
179
+ return this.evaluate(
180
+ {
181
+ content: `Tool call: ${toolName}`,
182
+ content_type: "tool_call",
183
+ action: "call_tool",
184
+ tool: { name: toolName, is_builtin: false, arguments: args },
185
+ ...rest
186
+ },
187
+ { timeout }
188
+ );
189
+ }
190
+ /** Stream guard evaluation results (POST /v1/guard/stream). */
191
+ async *stream(request, options) {
192
+ yield* this._client._stream("/v1/guard/stream", request, options?.timeout);
193
+ }
194
+ };
195
+ var DetectResource = class {
196
+ constructor(_client) {
197
+ this._client = _client;
198
+ }
199
+ /** Run detectors without policy evaluation (POST /v1/detect). */
200
+ async run(request, options) {
201
+ return this._client._postJSON("/v1/detect", request, options?.timeout);
202
+ }
203
+ };
204
+ var DetectorsResource = class {
205
+ constructor(_client) {
206
+ this._client = _client;
207
+ }
208
+ /** List available detectors (GET /v1/detectors). */
209
+ async list(options) {
210
+ return this._client._getJSON("/v1/detectors", options?.timeout);
211
+ }
212
+ };
213
+ var DebugResource = class {
214
+ constructor(_client) {
215
+ this._client = _client;
216
+ }
217
+ /** Inspect loaded policies (GET /v1/debug/policies). */
218
+ async policies(product = "guardrails", options) {
219
+ return this._client._getJSON(
220
+ `/v1/debug/policies?product=${product}`,
221
+ options?.timeout
222
+ );
223
+ }
224
+ };
225
+ var Highflame = class {
226
+ #baseUrl;
227
+ #tokenUrl;
228
+ #apiKey;
229
+ #timeout;
230
+ #maxRetries;
231
+ #overrideAccountId;
232
+ #overrideProjectId;
233
+ #defaultHeaders;
234
+ #staticHeaders;
235
+ #log;
236
+ #cachedToken = null;
237
+ #tokenPromise = null;
238
+ guard;
239
+ detect;
240
+ detectors;
241
+ debug;
242
+ constructor(options) {
243
+ const baseUrl = options.baseUrl ?? SAAS_BASE_URL;
244
+ const tokenUrl = options.tokenUrl ?? SAAS_TOKEN_URL;
245
+ this.#baseUrl = baseUrl.replace(/\/$/, "");
246
+ this.#tokenUrl = options.apiKey.startsWith("hf_sk") ? tokenUrl : void 0;
247
+ this.#apiKey = options.apiKey;
248
+ this.#timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
249
+ this.#maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
250
+ this.#overrideAccountId = options.accountId;
251
+ this.#overrideProjectId = options.projectId;
252
+ this.#defaultHeaders = options.defaultHeaders ?? {};
253
+ this.#staticHeaders = {
254
+ Authorization: `Bearer ${options.apiKey}`,
255
+ "Content-Type": "application/json",
256
+ Accept: "application/json",
257
+ "User-Agent": USER_AGENT,
258
+ ...this.#defaultHeaders
259
+ };
260
+ if (options.accountId) this.#staticHeaders["X-Account-ID"] = options.accountId;
261
+ if (options.projectId) this.#staticHeaders["X-Project-ID"] = options.projectId;
262
+ this.#log = options.logger ?? NOOP_LOGGER;
263
+ this.guard = new GuardResource(this);
264
+ this.detect = new DetectResource(this);
265
+ this.detectors = new DetectorsResource(this);
266
+ this.debug = new DebugResource(this);
267
+ }
268
+ get accountId() {
269
+ return this.#overrideAccountId ?? this.#cachedToken?.accountId ?? "";
270
+ }
271
+ get projectId() {
272
+ return this.#overrideProjectId ?? this.#cachedToken?.projectId ?? "";
273
+ }
274
+ /** Get auth headers (exposed for external use with custom HTTP clients). */
275
+ async getAuthHeaders() {
276
+ if (!this.#tokenUrl) {
277
+ return this.#staticHeaders;
278
+ }
279
+ if (this.#cachedToken && Date.now() < this.#cachedToken.expiresAt) {
280
+ return this.#buildTokenHeaders(this.#cachedToken);
281
+ }
282
+ if (!this.#tokenPromise) {
283
+ this.#tokenPromise = this.#exchangeToken().finally(() => {
284
+ this.#tokenPromise = null;
285
+ });
286
+ }
287
+ this.#cachedToken = await this.#tokenPromise;
288
+ return this.#buildTokenHeaders(this.#cachedToken);
289
+ }
290
+ #buildTokenHeaders(token) {
291
+ const headers = {
292
+ Authorization: `Bearer ${token.accessToken}`,
293
+ "Content-Type": "application/json",
294
+ Accept: "application/json",
295
+ "User-Agent": USER_AGENT,
296
+ ...this.#defaultHeaders
297
+ };
298
+ const accountId = this.#overrideAccountId ?? (token.accountId || void 0);
299
+ const projectId = this.#overrideProjectId ?? (token.projectId || void 0);
300
+ if (accountId) headers["X-Account-ID"] = accountId;
301
+ if (projectId) headers["X-Project-ID"] = projectId;
302
+ return headers;
303
+ }
304
+ async #exchangeToken() {
305
+ this.#log.debug("Token exchange: POST %s", this.#tokenUrl);
306
+ const controller = new AbortController();
307
+ const timer = setTimeout(() => controller.abort(), this.#timeout);
308
+ let response;
309
+ try {
310
+ response = await fetch(this.#tokenUrl, {
311
+ method: "POST",
312
+ headers: { "Content-Type": "application/json", "User-Agent": USER_AGENT },
313
+ body: JSON.stringify({ grant_type: "api_key", api_key: this.#apiKey }),
314
+ signal: controller.signal
315
+ });
316
+ } catch (err) {
317
+ if (err instanceof Error && err.name === "AbortError") {
318
+ this.#log.warn("Token exchange timed out after %dms", this.#timeout);
319
+ throw new APIConnectionError(`Token exchange timed out after ${this.#timeout}ms`);
320
+ }
321
+ this.#log.warn("Token exchange failed: %s", err instanceof Error ? err.message : String(err));
322
+ throw new APIConnectionError(
323
+ `Token exchange failed: ${err instanceof Error ? err.message : String(err)}`
324
+ );
325
+ } finally {
326
+ clearTimeout(timer);
327
+ }
328
+ if (!response.ok) {
329
+ this.#log.warn("Token exchange error: %d %s", response.status, response.statusText);
330
+ throw await parseError(response);
331
+ }
332
+ const tok = await response.json();
333
+ this.#log.debug("Token exchange: success (expires_in=%ds)", tok.expires_in);
334
+ return {
335
+ accessToken: tok.access_token,
336
+ expiresAt: Date.now() + tok.expires_in * 1e3 - TOKEN_REFRESH_BUFFER_MS,
337
+ accountId: tok.account_id ?? "",
338
+ projectId: tok.project_id ?? "",
339
+ gatewayId: tok.gateway_id ?? ""
340
+ };
341
+ }
342
+ // -----------------------------------------------------------------------
343
+ // Internal HTTP helpers (used by resource classes)
344
+ // -----------------------------------------------------------------------
345
+ /** @internal */
346
+ async _fetchWithRetry(path, init, overrideTimeout) {
347
+ const effectiveTimeout = overrideTimeout ?? this.#timeout;
348
+ let lastError;
349
+ let idempotencyKey;
350
+ const method = (init.method ?? "GET").toUpperCase();
351
+ for (let attempt = 0; attempt <= this.#maxRetries; attempt++) {
352
+ if (attempt > 0) {
353
+ const delay = retryDelay(attempt - 1);
354
+ this.#log.debug(
355
+ "Retrying %s %s (attempt %d/%d) after %.0fms",
356
+ method,
357
+ path,
358
+ attempt + 1,
359
+ this.#maxRetries + 1,
360
+ delay
361
+ );
362
+ await sleep(delay);
363
+ if (!idempotencyKey) {
364
+ idempotencyKey = crypto.randomUUID();
365
+ }
366
+ }
367
+ this.#log.debug("%s %s", method, path);
368
+ if (init.body && typeof init.body === "string") {
369
+ this.#log.debug("Request body: %s", truncate(init.body));
370
+ }
371
+ const authHeaders = await this.getAuthHeaders();
372
+ if (idempotencyKey) {
373
+ authHeaders["X-Idempotency-Key"] = idempotencyKey;
374
+ }
375
+ const controller = new AbortController();
376
+ const timer = setTimeout(() => controller.abort(), effectiveTimeout);
377
+ let response;
378
+ try {
379
+ response = await fetch(this.#baseUrl + path, {
380
+ ...init,
381
+ headers: authHeaders,
382
+ signal: controller.signal
383
+ });
384
+ } catch (err) {
385
+ if (err instanceof Error && err.name === "AbortError") {
386
+ this.#log.debug("Request timed out: %s %s", method, path);
387
+ lastError = new APIConnectionError(`Request timed out after ${effectiveTimeout}ms`);
388
+ continue;
389
+ }
390
+ throw new APIConnectionError(
391
+ `Connection failed: ${err instanceof Error ? err.message : String(err)}`
392
+ );
393
+ } finally {
394
+ clearTimeout(timer);
395
+ }
396
+ this.#log.debug("%s %s \u2192 %d", method, path, response.status);
397
+ if (!RETRY_STATUS_CODES.has(response.status)) {
398
+ return response;
399
+ }
400
+ lastError = await parseError(response);
401
+ }
402
+ throw lastError;
403
+ }
404
+ /** @internal */
405
+ async _postJSON(path, body, overrideTimeout) {
406
+ const response = await this._fetchWithRetry(
407
+ path,
408
+ { method: "POST", body: JSON.stringify(body) },
409
+ overrideTimeout
410
+ );
411
+ if (!response.ok) {
412
+ throw await parseError(response);
413
+ }
414
+ return response.json();
415
+ }
416
+ /** @internal */
417
+ async _getJSON(path, overrideTimeout) {
418
+ const response = await this._fetchWithRetry(
419
+ path,
420
+ { method: "GET" },
421
+ overrideTimeout
422
+ );
423
+ if (!response.ok) {
424
+ throw await parseError(response);
425
+ }
426
+ return response.json();
427
+ }
428
+ /** @internal */
429
+ async *_stream(path, body, overrideTimeout) {
430
+ const effectiveTimeout = overrideTimeout ?? this.#timeout;
431
+ this.#log.debug("POST %s (stream)", path);
432
+ const authHeaders = await this.getAuthHeaders();
433
+ const controller = new AbortController();
434
+ const timer = setTimeout(() => controller.abort(), effectiveTimeout);
435
+ let response;
436
+ try {
437
+ response = await fetch(this.#baseUrl + path, {
438
+ method: "POST",
439
+ headers: { ...authHeaders, Accept: "text/event-stream" },
440
+ body: JSON.stringify(body),
441
+ signal: controller.signal
442
+ });
443
+ } catch (err) {
444
+ clearTimeout(timer);
445
+ if (err instanceof Error && err.name === "AbortError") {
446
+ this.#log.debug("Stream timed out: POST %s", path);
447
+ throw new APIConnectionError(`Stream timed out after ${effectiveTimeout}ms`);
448
+ }
449
+ throw new APIConnectionError(
450
+ `Connection failed: ${err instanceof Error ? err.message : String(err)}`
451
+ );
452
+ }
453
+ this.#log.debug("POST %s (stream) \u2192 %d", path, response.status);
454
+ if (!response.ok) {
455
+ clearTimeout(timer);
456
+ throw await parseError(response);
457
+ }
458
+ try {
459
+ yield* streamSseResponse(response);
460
+ } finally {
461
+ clearTimeout(timer);
462
+ }
463
+ }
464
+ toString() {
465
+ return `Highflame(baseUrl=${JSON.stringify(this.#baseUrl)})`;
466
+ }
467
+ };
468
+
469
+ // src/shield.ts
470
+ function splitOnTopLevelCommas(s) {
471
+ const parts = [];
472
+ let depth = 0;
473
+ let inString = null;
474
+ let cur = "";
475
+ let i = 0;
476
+ while (i < s.length) {
477
+ const ch = s[i];
478
+ if (inString !== null) {
479
+ cur += ch;
480
+ if (ch === "\\") {
481
+ i++;
482
+ if (i < s.length) cur += s[i];
483
+ } else if (ch === inString) {
484
+ inString = null;
485
+ }
486
+ } else if (ch === '"' || ch === "'" || ch === "`") {
487
+ inString = ch;
488
+ cur += ch;
489
+ } else if (ch === "(" || ch === "[" || ch === "{") {
490
+ depth++;
491
+ cur += ch;
492
+ } else if (ch === ")" || ch === "]" || ch === "}") {
493
+ depth--;
494
+ cur += ch;
495
+ } else if (ch === "," && depth === 0) {
496
+ parts.push(cur);
497
+ cur = "";
498
+ } else {
499
+ cur += ch;
500
+ }
501
+ i++;
502
+ }
503
+ if (cur) parts.push(cur);
504
+ return parts;
505
+ }
506
+ function getParamNames(fn) {
507
+ try {
508
+ const src = fn.toString().replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, "");
509
+ const headerMatch = src.match(/^(?:async\s+)?(?:function\s*\w*\s*|\w+\s*)?\(/);
510
+ if (!headerMatch) {
511
+ const singleParam = src.match(/^(?:async\s+)?(\w+)\s*=>/);
512
+ if (singleParam) return [singleParam[1] ?? "arg0"];
513
+ return [];
514
+ }
515
+ const openIdx = headerMatch[0].length - 1;
516
+ let depth = 0;
517
+ let closeIdx = -1;
518
+ for (let i = openIdx; i < src.length; i++) {
519
+ if (src[i] === "(") depth++;
520
+ else if (src[i] === ")") {
521
+ if (--depth === 0) {
522
+ closeIdx = i;
523
+ break;
524
+ }
525
+ }
526
+ }
527
+ if (closeIdx === -1) return [];
528
+ const inner = src.slice(openIdx + 1, closeIdx).trim();
529
+ if (!inner) return [];
530
+ return splitOnTopLevelCommas(inner).map(
531
+ (p) => p.trim().replace(/[=:].*/s, "").replace(/^\.\.\./, "").replace(/[{}[\]]/g, "").trim()
532
+ ).filter(Boolean);
533
+ } catch {
534
+ return [];
535
+ }
536
+ }
537
+ function buildArgsDict(fn, args) {
538
+ const names = getParamNames(fn);
539
+ const result = {};
540
+ for (let i = 0; i < args.length; i++) {
541
+ result[names[i] ?? `arg${i}`] = args[i];
542
+ }
543
+ return result;
544
+ }
545
+ function raiseIfBlocked(response) {
546
+ if (response.decision === "deny") {
547
+ throw new BlockedError(response);
548
+ }
549
+ }
550
+ var Shield = class {
551
+ constructor(client) {
552
+ this.client = client;
553
+ }
554
+ prompt(fn, options) {
555
+ const argIdx = options?.contentArg ?? 0;
556
+ const { mode, sessionId } = options ?? {};
557
+ const wrapper = async (...args) => {
558
+ const content = args[argIdx];
559
+ if (typeof content !== "string") {
560
+ throw new TypeError(
561
+ `shield.prompt: argument at index ${argIdx} must be string, got ${typeof content}`
562
+ );
563
+ }
564
+ raiseIfBlocked(
565
+ await this.client.guard.evaluatePrompt(content, { mode, session_id: sessionId })
566
+ );
567
+ return fn(...args);
568
+ };
569
+ Object.defineProperty(wrapper, "name", { value: fn.name, configurable: true });
570
+ return wrapper;
571
+ }
572
+ tool(fn, options) {
573
+ const toolName = options?.toolName ?? fn.name;
574
+ const { mode, sessionId } = options ?? {};
575
+ const wrapper = async (...args) => {
576
+ const argsDict = buildArgsDict(fn, args);
577
+ raiseIfBlocked(
578
+ await this.client.guard.evaluateToolCall(toolName, argsDict, {
579
+ mode,
580
+ session_id: sessionId
581
+ })
582
+ );
583
+ return fn(...args);
584
+ };
585
+ Object.defineProperty(wrapper, "name", { value: fn.name, configurable: true });
586
+ return wrapper;
587
+ }
588
+ toolResponse(fn, options) {
589
+ const toolName = options?.toolName ?? fn.name;
590
+ const { mode, sessionId } = options ?? {};
591
+ const wrapper = async (...args) => {
592
+ const result = await fn(...args);
593
+ raiseIfBlocked(
594
+ await this.client.guard.evaluate({
595
+ content: typeof result === "string" ? result : String(result),
596
+ content_type: "response",
597
+ action: "call_tool",
598
+ mode,
599
+ session_id: sessionId,
600
+ tool: { name: toolName, is_builtin: false }
601
+ })
602
+ );
603
+ return result;
604
+ };
605
+ Object.defineProperty(wrapper, "name", { value: fn.name, configurable: true });
606
+ return wrapper;
607
+ }
608
+ modelResponse(fn, options) {
609
+ const { mode, sessionId } = options ?? {};
610
+ const wrapper = async (...args) => {
611
+ const result = await fn(...args);
612
+ raiseIfBlocked(
613
+ await this.client.guard.evaluate({
614
+ content: typeof result === "string" ? result : String(result),
615
+ content_type: "response",
616
+ action: "process_prompt",
617
+ mode,
618
+ session_id: sessionId
619
+ })
620
+ );
621
+ return result;
622
+ };
623
+ Object.defineProperty(wrapper, "name", { value: fn.name, configurable: true });
624
+ return wrapper;
625
+ }
626
+ wrap(options) {
627
+ const { contentType, action, contentArg: argIdx = 0, mode, sessionId } = options;
628
+ return (fn) => {
629
+ const wrapper = async (...args) => {
630
+ const content = args[argIdx];
631
+ if (typeof content !== "string") {
632
+ throw new TypeError(
633
+ `shield.wrap: argument at index ${argIdx} must be string, got ${typeof content}`
634
+ );
635
+ }
636
+ raiseIfBlocked(
637
+ await this.client.guard.evaluate({
638
+ content,
639
+ content_type: contentType,
640
+ action,
641
+ mode,
642
+ session_id: sessionId
643
+ })
644
+ );
645
+ return fn(...args);
646
+ };
647
+ Object.defineProperty(wrapper, "name", { value: fn.name, configurable: true });
648
+ return wrapper;
649
+ };
650
+ }
651
+ };
652
+ export {
653
+ APIConnectionError,
654
+ APIError,
655
+ AuthenticationError,
656
+ BlockedError,
657
+ DebugResource,
658
+ DetectResource,
659
+ DetectorsResource,
660
+ GuardResource,
661
+ Highflame,
662
+ HighflameError,
663
+ RateLimitError,
664
+ Shield,
665
+ VERSION
666
+ };
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "highflame",
3
+ "version": "0.2.0",
4
+ "description": "JavaScript/TypeScript SDK for Highflame AI guardrails",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js",
11
+ "require": "./dist/index.cjs"
12
+ }
13
+ },
14
+ "main": "./dist/index.cjs",
15
+ "module": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsup src/index.ts --format esm,cjs --dts --clean",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest",
24
+ "typecheck": "tsc --noEmit",
25
+ "lint": "eslint src tests",
26
+ "lint:fix": "eslint src tests --fix",
27
+ "format": "prettier --write src tests smoke_test.mjs",
28
+ "format:check": "prettier --check src tests smoke_test.mjs",
29
+ "check": "tsc --noEmit && eslint src tests",
30
+ "coverage": "vitest run --coverage"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^20",
34
+ "@vitest/coverage-v8": "^2",
35
+ "eslint": "^9",
36
+ "msw": "^2",
37
+ "prettier": "^3",
38
+ "tsup": "^8",
39
+ "typescript": "^5.4",
40
+ "typescript-eslint": "^8",
41
+ "vitest": "^2"
42
+ },
43
+ "engines": {
44
+ "node": ">=18"
45
+ }
46
+ }