@gurulu/node 1.0.1 → 1.0.3

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.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type LlmCaptureInput, type WrapOptions } from './llm.ts';
1
2
  import { type ExpressMiddlewareOptions } from './middleware/express.ts';
2
3
  import { type FastifyPluginOptions } from './middleware/fastify.ts';
3
4
  import { createNextHandler, type NextHandlerOptions } from './middleware/next.ts';
@@ -16,6 +17,22 @@ export declare class Gurulu {
16
17
  identify(externalUserId: string, traits?: IdentifyTraits, explicitContext?: ServerContext): Promise<IdentifyResult>;
17
18
  /** Outcome event track (queue + auto-flush). */
18
19
  track(eventKey: string, properties?: Record<string, unknown>, explicitContext?: ServerContext, eventType?: EventClass): TrackResult;
20
+ /**
21
+ * M46 LLM Analytics (K31) — müşterinin AI özelliği için `llm_request` capture.
22
+ * Interaction (gözlem) — outcome ÜRETMEZ (K16). Content default kapalı; opt-in
23
+ * için input.promptContent/responseContent + captureContent.
24
+ */
25
+ get llm(): {
26
+ capture: (input: LlmCaptureInput, captureContent?: boolean) => TrackResult;
27
+ };
28
+ /**
29
+ * OpenAI client'ı yerinde instrument eder — her chat/embedding çağrısı
30
+ * `llm_request` gönderir (token/latency/status otomatik). Zero-dep: OpenAI SDK
31
+ * import edilmez, structural typing. `const ai = gurulu.wrapOpenAI(openai)`.
32
+ */
33
+ wrapOpenAI<T>(client: T, opts?: WrapOptions): T;
34
+ /** Anthropic client'ı yerinde instrument eder (messages.create). */
35
+ wrapAnthropic<T>(client: T, opts?: WrapOptions): T;
19
36
  /** Manual flush (force send current queue). */
20
37
  flush(): Promise<FlushResult>;
21
38
  /** Graceful shutdown — flush + cancel timer + max 10s timeout. */
@@ -1 +1 @@
1
- {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAKA,OAAO,EAA2B,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACjG,OAAO,EAAuB,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAIlF,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,cAAc,EACd,cAAc,EACd,aAAa,EAGb,aAAa,EACb,eAAe,EACf,WAAW,EACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,oBAAoB,EAE1B,MAAM,sBAAsB,CAAC;AA2C9B,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,cAAc,CAA6B;gBAEvC,OAAO,CAAC,EAAE,eAAe;IAIrC,6DAA6D;IAC7D,IAAI,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI;IAOlC,OAAO,CAAC,aAAa;IAKrB,uDAAuD;IACjD,QAAQ,CACZ,cAAc,EAAE,MAAM,EACtB,MAAM,CAAC,EAAE,cAAc,EACvB,eAAe,CAAC,EAAE,aAAa,GAC9B,OAAO,CAAC,cAAc,CAAC;IAO1B,gDAAgD;IAChD,KAAK,CACH,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,eAAe,CAAC,EAAE,aAAa,EAC/B,SAAS,GAAE,UAAsB,GAChC,WAAW;IAad,+CAA+C;IACzC,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC;IAKnC,kEAAkE;IAC5D,QAAQ,CAAC,SAAS,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IASxD,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,aAAa;IAUrB,+CAA+C;IAC/C,IAAI,QAAQ;;;qFA5BS,CAAC;iGAOnB,CAAC;;;;;mGAjCgB,CAAC;;;;;6GAIQ,CAAC;;0BA2DR,0BAA0B,KAAG,oBAAoB;MAGtE;IAED,qDAAqD;IACrD,IAAI,OAAO;4BACoB,wBAAwB;MACtD;IAED,IAAI,OAAO;wBACgB,oBAAoB;MAC9C;IAED,IAAI,IAAI;;MAEP;CACF;AAED,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAE5D;AAKD,wBAAgB,UAAU,IAAI,MAAM,CAGnC;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAI3D;AAED,YAAY,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,WAAW,EAGjB,MAAM,UAAU,CAAC;AAClB,OAAO,EAA2B,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACjG,OAAO,EAAuB,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAIlF,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,cAAc,EACd,cAAc,EACd,aAAa,EAGb,aAAa,EACb,eAAe,EACf,WAAW,EACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,oBAAoB,EAE1B,MAAM,sBAAsB,CAAC;AA2C9B,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,cAAc,CAA6B;gBAEvC,OAAO,CAAC,EAAE,eAAe;IAIrC,6DAA6D;IAC7D,IAAI,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI;IAOlC,OAAO,CAAC,aAAa;IAKrB,uDAAuD;IACjD,QAAQ,CACZ,cAAc,EAAE,MAAM,EACtB,MAAM,CAAC,EAAE,cAAc,EACvB,eAAe,CAAC,EAAE,aAAa,GAC9B,OAAO,CAAC,cAAc,CAAC;IAO1B,gDAAgD;IAChD,KAAK,CACH,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,eAAe,CAAC,EAAE,aAAa,EAC/B,SAAS,GAAE,UAAsB,GAChC,WAAW;IAad;;;;OAIG;IACH,IAAI,GAAG;yBAGc,eAAe,+BAA2B,WAAW;MAQzE;IAED;;;;OAIG;IACH,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,CAAC;IAW/C,oEAAoE;IACpE,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,CAAC;IAWlD,+CAA+C;IACzC,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC;IAKnC,kEAAkE;IAC5D,QAAQ,CAAC,SAAS,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IASxD,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,aAAa;IAUrB,+CAA+C;IAC/C,IAAI,QAAQ;;;qFA5E2C,CAAA;iGAGf,CAAC;;;;;mGAjCR,CAAC;;;;;6GAMJ,CAAA;;0BA6GR,0BAA0B,KAAG,oBAAoB;MAGtE;IAED,qDAAqD;IACrD,IAAI,OAAO;4BACoB,wBAAwB;MACtD;IAED,IAAI,OAAO;wBACgB,oBAAoB;MAC9C;IAED,IAAI,IAAI;;MAEP;CACF;AAED,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAE5D;AAKD,wBAAgB,UAAU,IAAI,MAAM,CAGnC;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAI3D;AAED,YAAY,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,CAAC"}
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export declare const VERSION = "0.1.0";
2
2
  export { contextStorage, getContext, mergeContext, runWithContext } from './context.ts';
3
3
  export { createGurulu, Gurulu, getDefault, initDefault } from './core.ts';
4
4
  export { GuruluSDKError, InvalidWorkspaceKeyError, NotInitializedError, QueueOverflowError, TransportError, WebhookMappingNotFoundError, WebhookSignatureError, } from './errors.ts';
5
+ export { buildLlmProperties, type LlmCaptureFn, type LlmCaptureInput, type LlmOperation, type LlmProvider, type LlmStatus, type WrapOptions, wrapAnthropicClient, wrapOpenAIClient, } from './llm.ts';
5
6
  export { createExpressMiddleware, type ExpressMiddlewareOptions, } from './middleware/express.ts';
6
7
  export { createFastifyPlugin, type FastifyPluginOptions } from './middleware/fastify.ts';
7
8
  export { createNextHandler, type NextHandlerOptions } from './middleware/next.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,OAAO,UAAU,CAAC;AAG/B,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAExF,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAG1E,OAAO,EACL,cAAc,EACd,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,2BAA2B,EAC3B,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,uBAAuB,EACvB,KAAK,wBAAwB,GAC9B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAElF,YAAY,EACV,UAAU,EACV,WAAW,EACX,YAAY,EACZ,cAAc,EACd,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACrB,aAAa,EACb,cAAc,EACd,eAAe,EACf,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAExF,OAAO,EACL,4BAA4B,EAC5B,KAAK,yBAAyB,EAC9B,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,KAAK,oBAAoB,EACzB,aAAa,GACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,+BAA+B,EAC/B,KAAK,mBAAmB,EACxB,YAAY,GACb,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,OAAO,UAAU,CAAC;AAG/B,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAExF,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAG1E,OAAO,EACL,cAAc,EACd,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,2BAA2B,EAC3B,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,uBAAuB,EACvB,KAAK,wBAAwB,GAC9B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAElF,YAAY,EACV,UAAU,EACV,WAAW,EACX,YAAY,EACZ,cAAc,EACd,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACrB,aAAa,EACb,cAAc,EACd,eAAe,EACf,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAExF,OAAO,EACL,4BAA4B,EAC5B,KAAK,yBAAyB,EAC9B,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,KAAK,oBAAoB,EACzB,aAAa,GACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,+BAA+B,EAC/B,KAAK,mBAAmB,EACxB,YAAY,GACb,MAAM,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -548,6 +548,181 @@ function buildIdentify(input) {
548
548
  return payload;
549
549
  }
550
550
 
551
+ // src/llm.ts
552
+ function buildLlmProperties(input, captureContent) {
553
+ const total = input.totalTokens ?? input.promptTokens + input.completionTokens;
554
+ const props = {
555
+ provider: input.provider,
556
+ model: input.model,
557
+ operation: input.operation,
558
+ prompt_tokens: input.promptTokens,
559
+ completion_tokens: input.completionTokens,
560
+ total_tokens: total,
561
+ latency_ms: input.latencyMs,
562
+ status: input.status
563
+ };
564
+ if (input.cost != null)
565
+ props.cost = input.cost;
566
+ if (input.currency != null)
567
+ props.currency = input.currency;
568
+ if (input.errorType != null)
569
+ props.error_type = input.errorType;
570
+ if (input.feature != null)
571
+ props.feature = input.feature;
572
+ if (input.cacheHit != null)
573
+ props.cache_hit = input.cacheHit;
574
+ if (input.stream != null)
575
+ props.stream = input.stream;
576
+ if (captureContent) {
577
+ if (input.promptContent !== undefined)
578
+ props.prompt_content = input.promptContent;
579
+ if (input.responseContent !== undefined)
580
+ props.response_content = input.responseContent;
581
+ }
582
+ return props;
583
+ }
584
+ function asRecord(v) {
585
+ return typeof v === "object" && v !== null ? v : null;
586
+ }
587
+ function numField(rec, key) {
588
+ const v = rec?.[key];
589
+ return typeof v === "number" ? v : 0;
590
+ }
591
+ function extractOpenAIUsage(result) {
592
+ const rec = asRecord(result);
593
+ const usage = asRecord(rec?.usage);
594
+ if (!usage)
595
+ return null;
596
+ const cachedRec = asRecord(usage.prompt_tokens_details);
597
+ const cached = numField(cachedRec, "cached_tokens");
598
+ return {
599
+ promptTokens: numField(usage, "prompt_tokens"),
600
+ completionTokens: numField(usage, "completion_tokens"),
601
+ model: typeof rec?.model === "string" ? rec.model : null,
602
+ ...cached > 0 ? { cacheHit: true } : {}
603
+ };
604
+ }
605
+ function extractAnthropicUsage(result) {
606
+ const rec = asRecord(result);
607
+ const usage = asRecord(rec?.usage);
608
+ if (!usage)
609
+ return null;
610
+ const cacheRead = numField(usage, "cache_read_input_tokens");
611
+ return {
612
+ promptTokens: numField(usage, "input_tokens"),
613
+ completionTokens: numField(usage, "output_tokens"),
614
+ model: typeof rec?.model === "string" ? rec.model : null,
615
+ ...cacheRead > 0 ? { cacheHit: true } : {}
616
+ };
617
+ }
618
+ function classifyError(err) {
619
+ const rec = asRecord(err);
620
+ const httpStatus = typeof rec?.status === "number" ? rec.status : undefined;
621
+ const name = typeof rec?.name === "string" ? rec.name : "Error";
622
+ if (httpStatus === 429)
623
+ return { status: "rate_limited", errorType: "rate_limit" };
624
+ if (name.toLowerCase().includes("timeout") || rec?.code === "ETIMEDOUT") {
625
+ return { status: "timeout", errorType: "timeout" };
626
+ }
627
+ if (httpStatus != null)
628
+ return { status: "error", errorType: `http_${httpStatus}` };
629
+ return { status: "error", errorType: name };
630
+ }
631
+ function instrumentCreate(owner, method, provider, operation, extractUsage, capture, opts) {
632
+ const original = owner[method];
633
+ if (typeof original !== "function")
634
+ return;
635
+ const fn = original;
636
+ owner[method] = function patched(...args) {
637
+ const params = asRecord(args[0]);
638
+ const isStream = params?.stream === true;
639
+ const start = Date.now();
640
+ let result;
641
+ try {
642
+ result = fn.apply(this, args);
643
+ } catch (err) {
644
+ emitError(err);
645
+ throw err;
646
+ }
647
+ if (result != null && typeof result.then === "function") {
648
+ return result.then((resolved) => {
649
+ emitSuccess(resolved, isStream);
650
+ return resolved;
651
+ }, (err) => {
652
+ emitError(err);
653
+ throw err;
654
+ });
655
+ }
656
+ emitSuccess(result, isStream);
657
+ return result;
658
+ function emitSuccess(resolved, stream) {
659
+ if (stream)
660
+ return;
661
+ const usage = extractUsage(resolved);
662
+ if (!usage)
663
+ return;
664
+ const fallbackModel = typeof params?.model === "string" ? params.model : "unknown";
665
+ capture({
666
+ provider,
667
+ model: usage.model ?? fallbackModel,
668
+ operation,
669
+ promptTokens: usage.promptTokens,
670
+ completionTokens: usage.completionTokens,
671
+ latencyMs: Date.now() - start,
672
+ status: "success",
673
+ ...usage.cacheHit != null ? { cacheHit: usage.cacheHit } : {},
674
+ ...opts.feature != null ? { feature: opts.feature } : {},
675
+ ...opts.captureContent ? { promptContent: params?.messages ?? params?.input ?? params?.prompt } : {},
676
+ ...opts.captureContent ? { responseContent: resolved } : {}
677
+ });
678
+ }
679
+ function emitError(err) {
680
+ const { status, errorType } = classifyError(err);
681
+ const fallbackModel = typeof params?.model === "string" ? params.model : "unknown";
682
+ capture({
683
+ provider,
684
+ model: fallbackModel,
685
+ operation,
686
+ promptTokens: 0,
687
+ completionTokens: 0,
688
+ latencyMs: Date.now() - start,
689
+ status,
690
+ errorType,
691
+ ...opts.feature != null ? { feature: opts.feature } : {}
692
+ });
693
+ }
694
+ };
695
+ }
696
+ function wrapOpenAIClient(capture, client, opts = {}) {
697
+ const root = asRecord(client);
698
+ if (!root)
699
+ return client;
700
+ const chat = asRecord(root.chat);
701
+ const completions = asRecord(chat?.completions);
702
+ if (completions) {
703
+ instrumentCreate(completions, "create", "openai", "chat", extractOpenAIUsage, capture, opts);
704
+ }
705
+ const embeddings = asRecord(root.embeddings);
706
+ if (embeddings) {
707
+ instrumentCreate(embeddings, "create", "openai", "embedding", extractOpenAIUsage, capture, opts);
708
+ }
709
+ const responses = asRecord(root.responses);
710
+ if (responses) {
711
+ instrumentCreate(responses, "create", "openai", "chat", extractOpenAIUsage, capture, opts);
712
+ }
713
+ return client;
714
+ }
715
+ function wrapAnthropicClient(capture, client, opts = {}) {
716
+ const root = asRecord(client);
717
+ if (!root)
718
+ return client;
719
+ const messages = asRecord(root.messages);
720
+ if (messages) {
721
+ instrumentCreate(messages, "create", "anthropic", "chat", extractAnthropicUsage, capture, opts);
722
+ }
723
+ return client;
724
+ }
725
+
551
726
  // src/transport.ts
552
727
  var USER_AGENT = `gurulu-node/0.1.0 (${process.platform}; node ${process.version})`;
553
728
  function sleep(ms) {
@@ -576,7 +751,7 @@ async function postWithRetry(config, input) {
576
751
  headers: {
577
752
  "content-type": "application/json",
578
753
  "user-agent": USER_AGENT,
579
- "x-gurulu-key": config.workspaceKey
754
+ authorization: `Bearer ${config.workspaceKey}`
580
755
  },
581
756
  body: payload
582
757
  });
@@ -840,6 +1015,24 @@ class Gurulu {
840
1015
  const res = this.queue?.enqueue(event) ?? { queued: false, dropped: 0 };
841
1016
  return { queued: res.queued, queueSize: this.queue?.size() ?? 0 };
842
1017
  }
1018
+ get llm() {
1019
+ this.requireConfig();
1020
+ return {
1021
+ capture: (input, captureContent = false) => this.track("llm_request", buildLlmProperties(input, captureContent), undefined, "interaction")
1022
+ };
1023
+ }
1024
+ wrapOpenAI(client, opts) {
1025
+ const captureContent = opts?.captureContent ?? false;
1026
+ return wrapOpenAIClient((input) => {
1027
+ this.llm.capture(input, captureContent);
1028
+ }, client, opts);
1029
+ }
1030
+ wrapAnthropic(client, opts) {
1031
+ const captureContent = opts?.captureContent ?? false;
1032
+ return wrapAnthropicClient((input) => {
1033
+ this.llm.capture(input, captureContent);
1034
+ }, client, opts);
1035
+ }
843
1036
  async flush() {
844
1037
  this.requireConfig();
845
1038
  return await this.queue?.flush() ?? { attempted: 0, succeeded: 0, dropped: 0 };
@@ -915,6 +1108,8 @@ function initDefault(config) {
915
1108
  // src/index.ts
916
1109
  var VERSION = "0.1.0";
917
1110
  export {
1111
+ wrapOpenAIClient,
1112
+ wrapAnthropicClient,
918
1113
  verifyStripe,
919
1114
  verifyShopify,
920
1115
  verifyLemonSqueezy,
@@ -931,6 +1126,7 @@ export {
931
1126
  createFastifyPlugin,
932
1127
  createExpressMiddleware,
933
1128
  contextStorage,
1129
+ buildLlmProperties,
934
1130
  WebhookSignatureError,
935
1131
  WebhookMappingNotFoundError,
936
1132
  VERSION,
package/dist/llm.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ export type LlmProvider = 'openai' | 'anthropic' | 'google' | 'azure' | 'bedrock' | 'local' | 'other';
2
+ export type LlmOperation = 'chat' | 'completion' | 'embedding' | 'rerank' | 'image';
3
+ export type LlmStatus = 'success' | 'error' | 'timeout' | 'rate_limited';
4
+ export interface LlmCaptureInput {
5
+ provider: LlmProvider | string;
6
+ model: string;
7
+ operation: LlmOperation | string;
8
+ promptTokens: number;
9
+ completionTokens: number;
10
+ /** Yoksa prompt+completion (capture türetir). */
11
+ totalTokens?: number;
12
+ latencyMs: number;
13
+ status: LlmStatus | string;
14
+ /** Müşteri ham $ cost — verilirse backend bunu kullanır (yoksa map'ten türer). */
15
+ cost?: number;
16
+ currency?: string;
17
+ errorType?: string;
18
+ /** Müşterinin AI özellik adı (chatbot/rag/copilot) — gruplama. */
19
+ feature?: string;
20
+ cacheHit?: boolean;
21
+ stream?: boolean;
22
+ /** Opt-in içerik — sadece captureContent:true ile gönderilir (K31). */
23
+ promptContent?: unknown;
24
+ responseContent?: unknown;
25
+ }
26
+ export interface WrapOptions {
27
+ /** AI özellik adı — yakalanan tüm çağrılara feature olarak eklenir. */
28
+ feature?: string;
29
+ /** Opt-in: prompt/response gövdesini de gönder (default false). */
30
+ captureContent?: boolean;
31
+ }
32
+ /** LlmCaptureInput → registry `llm_request` property paketi (snake_case, K17). */
33
+ export declare function buildLlmProperties(input: LlmCaptureInput, captureContent: boolean): Record<string, unknown>;
34
+ /** capture callback — Gurulu.llm.capture'a bağlanır. */
35
+ export type LlmCaptureFn = (input: LlmCaptureInput) => void;
36
+ /** OpenAI client'ı yerinde instrument eder (chat.completions + embeddings + responses). */
37
+ export declare function wrapOpenAIClient<T>(capture: LlmCaptureFn, client: T, opts?: WrapOptions): T;
38
+ /** Anthropic client'ı yerinde instrument eder (messages.create). */
39
+ export declare function wrapAnthropicClient<T>(capture: LlmCaptureFn, client: T, opts?: WrapOptions): T;
40
+ //# sourceMappingURL=llm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,WAAW,GACnB,QAAQ,GACR,WAAW,GACX,QAAQ,GACR,OAAO,GACP,SAAS,GACT,OAAO,GACP,OAAO,CAAC;AAEZ,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;AACpF,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,cAAc,CAAC;AAEzE,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,WAAW,GAAG,MAAM,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,YAAY,GAAG,MAAM,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;IAC3B,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,eAAe,EACtB,cAAc,EAAE,OAAO,GACtB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwBzB;AAED,wDAAwD;AACxD,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;AA0J5D,2FAA2F;AAC3F,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,GAAE,WAAgB,GAAG,CAAC,CAyB/F;AAED,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,CAAC,EACT,IAAI,GAAE,WAAgB,GACrB,CAAC,CAQH"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gurulu/node",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "publishConfig": {