@highflame/sdk 0.3.4 → 0.3.5

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.cjs CHANGED
@@ -148,8 +148,53 @@ async function* streamSseResponse(response) {
148
148
  }
149
149
  }
150
150
 
151
+ // src/telemetry.ts
152
+ var _otelApi;
153
+ function getOtelApi() {
154
+ if (_otelApi !== void 0) return _otelApi;
155
+ try {
156
+ _otelApi = require("@opentelemetry/api");
157
+ } catch {
158
+ _otelApi = null;
159
+ }
160
+ return _otelApi;
161
+ }
162
+ function injectTraceContext(headers) {
163
+ const api = getOtelApi();
164
+ if (!api) return;
165
+ const propagator = api.propagation;
166
+ const context = api.context.active();
167
+ propagator.inject(context, headers, {
168
+ set(carrier, key, value) {
169
+ carrier[key] = value;
170
+ }
171
+ });
172
+ }
173
+ async function withSpan(name, attributes, fn) {
174
+ const api = getOtelApi();
175
+ if (!api) return fn();
176
+ const tracer = api.trace.getTracer("@highflame/sdk", VERSION);
177
+ const parentContext = api.context.active();
178
+ const span = tracer.startSpan(name, { attributes }, parentContext);
179
+ const spanContext = api.trace.setSpan(parentContext, span);
180
+ try {
181
+ const result = await api.context.with(spanContext, fn);
182
+ span.setStatus({ code: api.SpanStatusCode.OK });
183
+ return result;
184
+ } catch (err) {
185
+ span.setStatus({
186
+ code: api.SpanStatusCode.ERROR,
187
+ message: err instanceof Error ? err.message : String(err)
188
+ });
189
+ span.recordException(err instanceof Error ? err : new Error(String(err)));
190
+ throw err;
191
+ } finally {
192
+ span.end();
193
+ }
194
+ }
195
+
151
196
  // src/client.ts
152
- var VERSION = "0.2.0";
197
+ var VERSION = "0.3.4";
153
198
  var DEFAULT_TIMEOUT_MS = 3e4;
154
199
  var DEFAULT_MAX_RETRIES = 2;
155
200
  var RETRY_STATUS_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
@@ -201,7 +246,14 @@ var GuardResource = class {
201
246
  }
202
247
  /** Evaluate content against guard policies (POST /v1/guard). */
203
248
  async evaluate(request, options) {
204
- return this._client._postJSON("/v1/guard", request, options?.timeout);
249
+ return withSpan(
250
+ "highflame.guard",
251
+ {
252
+ "highflame.action": request.action ?? "process_prompt",
253
+ "highflame.content_type": request.content_type ?? "prompt"
254
+ },
255
+ () => this._client._postJSON("/v1/guard", request, options?.timeout)
256
+ );
205
257
  }
206
258
  /** Shorthand: evaluate a user prompt. */
207
259
  async evaluatePrompt(content, options) {
@@ -236,7 +288,11 @@ var DetectResource = class {
236
288
  }
237
289
  /** Run detectors without policy evaluation (POST /v1/detect). */
238
290
  async run(request, options) {
239
- return this._client._postJSON("/v1/detect", request, options?.timeout);
291
+ return withSpan(
292
+ "highflame.detect",
293
+ { "highflame.content_type": request.content_type ?? "prompt" },
294
+ () => this._client._postJSON("/v1/detect", request, options?.timeout)
295
+ );
240
296
  }
241
297
  };
242
298
  var DetectorsResource = class {
@@ -407,6 +463,7 @@ var Highflame = class {
407
463
  this.#log.debug("Request body: %s", truncate(init.body));
408
464
  }
409
465
  const authHeaders = await this.getAuthHeaders();
466
+ injectTraceContext(authHeaders);
410
467
  if (idempotencyKey) {
411
468
  authHeaders["X-Idempotency-Key"] = idempotencyKey;
412
469
  }
@@ -468,6 +525,7 @@ var Highflame = class {
468
525
  const effectiveTimeout = overrideTimeout ?? this.#timeout;
469
526
  this.#log.debug("POST %s (stream)", path);
470
527
  const authHeaders = await this.getAuthHeaders();
528
+ injectTraceContext(authHeaders);
471
529
  const controller = new AbortController();
472
530
  const timer = setTimeout(() => controller.abort(), effectiveTimeout);
473
531
  let response;
package/dist/index.d.cts CHANGED
@@ -553,7 +553,7 @@ interface TokenResponse {
553
553
  */
554
554
 
555
555
  /** SDK version — kept in sync with package.json via `make version-sync`. */
556
- declare const VERSION = "0.2.0";
556
+ declare const VERSION = "0.3.4";
557
557
  /**
558
558
  * Pluggable logger interface.
559
559
  *
package/dist/index.d.ts CHANGED
@@ -553,7 +553,7 @@ interface TokenResponse {
553
553
  */
554
554
 
555
555
  /** SDK version — kept in sync with package.json via `make version-sync`. */
556
- declare const VERSION = "0.2.0";
556
+ declare const VERSION = "0.3.4";
557
557
  /**
558
558
  * Pluggable logger interface.
559
559
  *
package/dist/index.js CHANGED
@@ -1,3 +1,10 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
1
8
  // src/errors.ts
2
9
  var HighflameError = class extends Error {
3
10
  constructor(message) {
@@ -110,8 +117,53 @@ async function* streamSseResponse(response) {
110
117
  }
111
118
  }
112
119
 
120
+ // src/telemetry.ts
121
+ var _otelApi;
122
+ function getOtelApi() {
123
+ if (_otelApi !== void 0) return _otelApi;
124
+ try {
125
+ _otelApi = __require("@opentelemetry/api");
126
+ } catch {
127
+ _otelApi = null;
128
+ }
129
+ return _otelApi;
130
+ }
131
+ function injectTraceContext(headers) {
132
+ const api = getOtelApi();
133
+ if (!api) return;
134
+ const propagator = api.propagation;
135
+ const context = api.context.active();
136
+ propagator.inject(context, headers, {
137
+ set(carrier, key, value) {
138
+ carrier[key] = value;
139
+ }
140
+ });
141
+ }
142
+ async function withSpan(name, attributes, fn) {
143
+ const api = getOtelApi();
144
+ if (!api) return fn();
145
+ const tracer = api.trace.getTracer("@highflame/sdk", VERSION);
146
+ const parentContext = api.context.active();
147
+ const span = tracer.startSpan(name, { attributes }, parentContext);
148
+ const spanContext = api.trace.setSpan(parentContext, span);
149
+ try {
150
+ const result = await api.context.with(spanContext, fn);
151
+ span.setStatus({ code: api.SpanStatusCode.OK });
152
+ return result;
153
+ } catch (err) {
154
+ span.setStatus({
155
+ code: api.SpanStatusCode.ERROR,
156
+ message: err instanceof Error ? err.message : String(err)
157
+ });
158
+ span.recordException(err instanceof Error ? err : new Error(String(err)));
159
+ throw err;
160
+ } finally {
161
+ span.end();
162
+ }
163
+ }
164
+
113
165
  // src/client.ts
114
- var VERSION = "0.2.0";
166
+ var VERSION = "0.3.4";
115
167
  var DEFAULT_TIMEOUT_MS = 3e4;
116
168
  var DEFAULT_MAX_RETRIES = 2;
117
169
  var RETRY_STATUS_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
@@ -163,7 +215,14 @@ var GuardResource = class {
163
215
  }
164
216
  /** Evaluate content against guard policies (POST /v1/guard). */
165
217
  async evaluate(request, options) {
166
- return this._client._postJSON("/v1/guard", request, options?.timeout);
218
+ return withSpan(
219
+ "highflame.guard",
220
+ {
221
+ "highflame.action": request.action ?? "process_prompt",
222
+ "highflame.content_type": request.content_type ?? "prompt"
223
+ },
224
+ () => this._client._postJSON("/v1/guard", request, options?.timeout)
225
+ );
167
226
  }
168
227
  /** Shorthand: evaluate a user prompt. */
169
228
  async evaluatePrompt(content, options) {
@@ -198,7 +257,11 @@ var DetectResource = class {
198
257
  }
199
258
  /** Run detectors without policy evaluation (POST /v1/detect). */
200
259
  async run(request, options) {
201
- return this._client._postJSON("/v1/detect", request, options?.timeout);
260
+ return withSpan(
261
+ "highflame.detect",
262
+ { "highflame.content_type": request.content_type ?? "prompt" },
263
+ () => this._client._postJSON("/v1/detect", request, options?.timeout)
264
+ );
202
265
  }
203
266
  };
204
267
  var DetectorsResource = class {
@@ -369,6 +432,7 @@ var Highflame = class {
369
432
  this.#log.debug("Request body: %s", truncate(init.body));
370
433
  }
371
434
  const authHeaders = await this.getAuthHeaders();
435
+ injectTraceContext(authHeaders);
372
436
  if (idempotencyKey) {
373
437
  authHeaders["X-Idempotency-Key"] = idempotencyKey;
374
438
  }
@@ -430,6 +494,7 @@ var Highflame = class {
430
494
  const effectiveTimeout = overrideTimeout ?? this.#timeout;
431
495
  this.#log.debug("POST %s (stream)", path);
432
496
  const authHeaders = await this.getAuthHeaders();
497
+ injectTraceContext(authHeaders);
433
498
  const controller = new AbortController();
434
499
  const timer = setTimeout(() => controller.abort(), effectiveTimeout);
435
500
  let response;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@highflame/sdk",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "description": "JavaScript/TypeScript SDK for Highflame AI guardrails",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -30,6 +30,7 @@
30
30
  "coverage": "vitest run --coverage"
31
31
  },
32
32
  "devDependencies": {
33
+ "@opentelemetry/api": "^1.9.0",
33
34
  "@types/node": "^20",
34
35
  "@vitest/coverage-v8": "^2",
35
36
  "eslint": "^9",
@@ -40,6 +41,14 @@
40
41
  "typescript-eslint": "^8",
41
42
  "vitest": "^2"
42
43
  },
44
+ "peerDependencies": {
45
+ "@opentelemetry/api": "^1.4.0"
46
+ },
47
+ "peerDependenciesMeta": {
48
+ "@opentelemetry/api": {
49
+ "optional": true
50
+ }
51
+ },
43
52
  "engines": {
44
53
  "node": ">=18"
45
54
  }