@waniwani/sdk 0.12.18 → 0.13.1

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
@@ -1,9 +1,22 @@
1
+ <div align="center">
2
+
1
3
  # @waniwani/sdk
2
4
 
3
- [![npm](https://img.shields.io/npm/v/@waniwani/sdk.svg)](https://www.npmjs.com/package/@waniwani/sdk)
4
- [![license](https://img.shields.io/npm/l/@waniwani/sdk.svg)](./LICENSE)
5
+ **The open-source TypeScript SDK for MCP funnels** — multi-step conversational flows (sales, lead generation, booking, quotes) that run as a single MCP tool inside ChatGPT, Claude, Cursor, and any MCP-capable client.
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@waniwani/sdk?labelColor=333333&color=666666)](https://www.npmjs.com/package/@waniwani/sdk)
8
+ [![npm downloads](https://img.shields.io/npm/dm/@waniwani/sdk?labelColor=333333&color=666666)](https://www.npmjs.com/package/@waniwani/sdk)
9
+ [![last commit](https://img.shields.io/github/last-commit/WaniWani-AI/sdk?labelColor=333333&color=666666)](https://github.com/WaniWani-AI/sdk/commits)
10
+ [![commit activity](https://img.shields.io/github/commit-activity/m/WaniWani-AI/sdk?labelColor=333333&color=666666)](https://github.com/WaniWani-AI/sdk/pulse)
11
+ [![stars](https://img.shields.io/github/stars/WaniWani-AI/sdk?labelColor=333333&color=666666)](https://github.com/WaniWani-AI/sdk/stargazers)
12
+ [![license](https://img.shields.io/npm/l/@waniwani/sdk?labelColor=333333&color=666666)](./LICENSE)
13
+ [![follow @waniwani_ai](https://img.shields.io/badge/follow-%40waniwani__ai-333333?logo=x&logoColor=white&labelColor=333333&color=666666)](https://x.com/waniwani_ai)
14
+
15
+ [**Docs**](https://docs.waniwani.ai) · [**Website**](https://waniwani.ai) · [**Dashboard**](https://app.waniwani.ai) · [**CLI**](https://www.npmjs.com/package/@waniwani/cli) · [**Issues**](https://github.com/WaniWani-AI/sdk/issues)
5
16
 
6
- The open-source TypeScript SDK for **MCP funnels**: multi-step conversational flows (sales, lead generation, booking, quotes) that run as a single MCP tool inside ChatGPT, Claude, Cursor, and any MCP-capable client. One typed state graph compiles to one MCP tool. MIT, bring your own store, optional hosted Platform via one env var.
17
+ </div>
18
+
19
+ One typed state graph compiles to one MCP tool. MIT, bring your own store, optional hosted Platform via one env var.
7
20
 
8
21
  Forked from production MCPs we shipped for paying customers (insurance quoting, pet care, lead capture, booking), and open-sourced once the shape stabilized.
9
22
 
@@ -132,6 +145,10 @@ Full docs at **[docs.waniwani.ai](https://docs.waniwani.ai)**. Same source as [`
132
145
  - **Dashboard:** [app.waniwani.ai](https://app.waniwani.ai)
133
146
  - **Issues:** [github.com/WaniWani-AI/sdk/issues](https://github.com/WaniWani-AI/sdk/issues)
134
147
 
148
+ ## Security
149
+
150
+ Found a vulnerability? Please report it privately — see [SECURITY.md](./SECURITY.md). Do not open a public issue for security reports.
151
+
135
152
  ## License
136
153
 
137
154
  [MIT](./LICENSE) © WaniWani
@@ -57,7 +57,7 @@ interface KbClient {
57
57
  sources(): Promise<KbSource[]>;
58
58
  }
59
59
 
60
- type EventType = "session.started" | "tool.called" | "quote.requested" | "quote.succeeded" | "quote.failed" | "link.clicked" | "purchase.completed" | "widget_render" | "widget_click" | "widget_link_click" | "widget_error" | "widget_scroll" | "widget_form_field" | "widget_form_submit" | "user.identified";
60
+ type EventType = "session.started" | "tool.called" | "quote.requested" | "quote.succeeded" | "quote.failed" | "link.clicked" | "purchase.completed" | "widget_render" | "widget_click" | "widget_link_click" | "widget_error" | "widget_scroll" | "widget_form_field" | "widget_form_submit" | "user.identified" | "price_shown" | "prices_compared" | "option_selected" | "lead" | "converted";
61
61
  interface ToolCalledProperties {
62
62
  name?: string;
63
63
  type?: "pricing" | "product_info" | "availability" | "support" | "other";
@@ -73,6 +73,34 @@ interface PurchaseCompletedProperties {
73
73
  amount?: number;
74
74
  currency?: string;
75
75
  }
76
+ interface PriceShownProperties {
77
+ amount: number;
78
+ currency: string;
79
+ itemId?: string;
80
+ label?: string;
81
+ }
82
+ interface ComparedPriceOption {
83
+ id: string;
84
+ amount: number;
85
+ currency: string;
86
+ }
87
+ interface PricesComparedProperties {
88
+ options: ComparedPriceOption[];
89
+ }
90
+ interface OptionSelectedProperties {
91
+ id: string;
92
+ amount: number;
93
+ currency: string;
94
+ }
95
+ interface LeadProperties {
96
+ source?: string;
97
+ }
98
+ interface ConvertedProperties {
99
+ amount: number;
100
+ currency: string;
101
+ /** When the conversion actually happened — for backdated off-platform sales. */
102
+ occurredAt?: string;
103
+ }
76
104
  interface TrackingContext {
77
105
  /**
78
106
  * MCP request metadata passed through to the API.
@@ -122,6 +150,21 @@ type TrackEvent = ({
122
150
  properties?: PurchaseCompletedProperties;
123
151
  } & BaseTrackEvent) | ({
124
152
  event: "user.identified";
153
+ } & BaseTrackEvent) | ({
154
+ event: "price_shown";
155
+ properties?: PriceShownProperties;
156
+ } & BaseTrackEvent) | ({
157
+ event: "prices_compared";
158
+ properties?: PricesComparedProperties;
159
+ } & BaseTrackEvent) | ({
160
+ event: "option_selected";
161
+ properties?: OptionSelectedProperties;
162
+ } & BaseTrackEvent) | ({
163
+ event: "lead";
164
+ properties?: LeadProperties;
165
+ } & BaseTrackEvent) | ({
166
+ event: "converted";
167
+ properties?: ConvertedProperties;
125
168
  } & BaseTrackEvent);
126
169
  /**
127
170
  * Legacy tracking shape supported for existing integrations.
@@ -141,6 +184,54 @@ interface LegacyTrackEvent extends TrackingContext {
141
184
  * Public track input accepted by `client.track()`.
142
185
  */
143
186
  type TrackInput = TrackEvent | LegacyTrackEvent;
187
+ interface RevenuePriceShownInput extends TrackingContext, PriceShownProperties {
188
+ }
189
+ interface RevenuePricesComparedInput extends TrackingContext, PricesComparedProperties {
190
+ }
191
+ interface RevenueOptionSelectedInput extends TrackingContext, OptionSelectedProperties {
192
+ }
193
+ /**
194
+ * Input for `track.lead()`. `source` is the lead's acquisition source
195
+ * (the `lead` event property, e.g. "newsletter") — on this helper it shadows
196
+ * the envelope `source` from the tracking context. To set a custom envelope
197
+ * source on a lead, use the generic `track({ event: "lead", … })`.
198
+ */
199
+ interface RevenueLeadInput extends TrackingContext, LeadProperties {
200
+ }
201
+ interface RevenueConvertedInput extends TrackingContext, ConvertedProperties {
202
+ }
203
+ /**
204
+ * Revenue-oriented helpers, flat on `client.track.*` (e.g.
205
+ * `client.track.priceShown()`, `client.track.converted()`). Decoupled from
206
+ * product primitives — each maps to a typed first-class revenue event.
207
+ */
208
+ interface RevenueTrackingApi {
209
+ priceShown: (input: RevenuePriceShownInput) => Promise<{
210
+ eventId: string;
211
+ }>;
212
+ pricesCompared: (input: RevenuePricesComparedInput) => Promise<{
213
+ eventId: string;
214
+ }>;
215
+ optionSelected: (input: RevenueOptionSelectedInput) => Promise<{
216
+ eventId: string;
217
+ }>;
218
+ lead: (input?: RevenueLeadInput) => Promise<{
219
+ eventId: string;
220
+ }>;
221
+ converted: (input: RevenueConvertedInput) => Promise<{
222
+ eventId: string;
223
+ }>;
224
+ }
225
+ /**
226
+ * `client.track` — callable for generic events (`track(event)`), with the
227
+ * revenue helpers attached flat: `track.priceShown()`, `track.lead()`,
228
+ * `track.converted()`, etc.
229
+ */
230
+ interface TrackFn extends RevenueTrackingApi {
231
+ (event: TrackInput): Promise<{
232
+ eventId: string;
233
+ }>;
234
+ }
144
235
  interface TrackingConfig {
145
236
  /** Events API V2 endpoint path. */
146
237
  endpointPath?: string;
@@ -180,10 +271,11 @@ interface TrackingClient {
180
271
  /**
181
272
  * Track an event using modern or legacy input shape.
182
273
  * Returns a deterministic event id immediately after enqueue.
274
+ *
275
+ * Also exposes the revenue helpers flat: `client.track.priceShown()`,
276
+ * `client.track.lead()`, `client.track.converted()`, etc.
183
277
  */
184
- track: (event: TrackInput) => Promise<{
185
- eventId: string;
186
- }>;
278
+ track: TrackFn;
187
279
  /**
188
280
  * Flush all currently buffered events.
189
281
  */
@@ -57,7 +57,7 @@ interface KbClient {
57
57
  sources(): Promise<KbSource[]>;
58
58
  }
59
59
 
60
- type EventType = "session.started" | "tool.called" | "quote.requested" | "quote.succeeded" | "quote.failed" | "link.clicked" | "purchase.completed" | "widget_render" | "widget_click" | "widget_link_click" | "widget_error" | "widget_scroll" | "widget_form_field" | "widget_form_submit" | "user.identified";
60
+ type EventType = "session.started" | "tool.called" | "quote.requested" | "quote.succeeded" | "quote.failed" | "link.clicked" | "purchase.completed" | "widget_render" | "widget_click" | "widget_link_click" | "widget_error" | "widget_scroll" | "widget_form_field" | "widget_form_submit" | "user.identified" | "price_shown" | "prices_compared" | "option_selected" | "lead" | "converted";
61
61
  interface ToolCalledProperties {
62
62
  name?: string;
63
63
  type?: "pricing" | "product_info" | "availability" | "support" | "other";
@@ -73,6 +73,34 @@ interface PurchaseCompletedProperties {
73
73
  amount?: number;
74
74
  currency?: string;
75
75
  }
76
+ interface PriceShownProperties {
77
+ amount: number;
78
+ currency: string;
79
+ itemId?: string;
80
+ label?: string;
81
+ }
82
+ interface ComparedPriceOption {
83
+ id: string;
84
+ amount: number;
85
+ currency: string;
86
+ }
87
+ interface PricesComparedProperties {
88
+ options: ComparedPriceOption[];
89
+ }
90
+ interface OptionSelectedProperties {
91
+ id: string;
92
+ amount: number;
93
+ currency: string;
94
+ }
95
+ interface LeadProperties {
96
+ source?: string;
97
+ }
98
+ interface ConvertedProperties {
99
+ amount: number;
100
+ currency: string;
101
+ /** When the conversion actually happened — for backdated off-platform sales. */
102
+ occurredAt?: string;
103
+ }
76
104
  interface TrackingContext {
77
105
  /**
78
106
  * MCP request metadata passed through to the API.
@@ -122,6 +150,21 @@ type TrackEvent = ({
122
150
  properties?: PurchaseCompletedProperties;
123
151
  } & BaseTrackEvent) | ({
124
152
  event: "user.identified";
153
+ } & BaseTrackEvent) | ({
154
+ event: "price_shown";
155
+ properties?: PriceShownProperties;
156
+ } & BaseTrackEvent) | ({
157
+ event: "prices_compared";
158
+ properties?: PricesComparedProperties;
159
+ } & BaseTrackEvent) | ({
160
+ event: "option_selected";
161
+ properties?: OptionSelectedProperties;
162
+ } & BaseTrackEvent) | ({
163
+ event: "lead";
164
+ properties?: LeadProperties;
165
+ } & BaseTrackEvent) | ({
166
+ event: "converted";
167
+ properties?: ConvertedProperties;
125
168
  } & BaseTrackEvent);
126
169
  /**
127
170
  * Legacy tracking shape supported for existing integrations.
@@ -141,6 +184,54 @@ interface LegacyTrackEvent extends TrackingContext {
141
184
  * Public track input accepted by `client.track()`.
142
185
  */
143
186
  type TrackInput = TrackEvent | LegacyTrackEvent;
187
+ interface RevenuePriceShownInput extends TrackingContext, PriceShownProperties {
188
+ }
189
+ interface RevenuePricesComparedInput extends TrackingContext, PricesComparedProperties {
190
+ }
191
+ interface RevenueOptionSelectedInput extends TrackingContext, OptionSelectedProperties {
192
+ }
193
+ /**
194
+ * Input for `track.lead()`. `source` is the lead's acquisition source
195
+ * (the `lead` event property, e.g. "newsletter") — on this helper it shadows
196
+ * the envelope `source` from the tracking context. To set a custom envelope
197
+ * source on a lead, use the generic `track({ event: "lead", … })`.
198
+ */
199
+ interface RevenueLeadInput extends TrackingContext, LeadProperties {
200
+ }
201
+ interface RevenueConvertedInput extends TrackingContext, ConvertedProperties {
202
+ }
203
+ /**
204
+ * Revenue-oriented helpers, flat on `client.track.*` (e.g.
205
+ * `client.track.priceShown()`, `client.track.converted()`). Decoupled from
206
+ * product primitives — each maps to a typed first-class revenue event.
207
+ */
208
+ interface RevenueTrackingApi {
209
+ priceShown: (input: RevenuePriceShownInput) => Promise<{
210
+ eventId: string;
211
+ }>;
212
+ pricesCompared: (input: RevenuePricesComparedInput) => Promise<{
213
+ eventId: string;
214
+ }>;
215
+ optionSelected: (input: RevenueOptionSelectedInput) => Promise<{
216
+ eventId: string;
217
+ }>;
218
+ lead: (input?: RevenueLeadInput) => Promise<{
219
+ eventId: string;
220
+ }>;
221
+ converted: (input: RevenueConvertedInput) => Promise<{
222
+ eventId: string;
223
+ }>;
224
+ }
225
+ /**
226
+ * `client.track` — callable for generic events (`track(event)`), with the
227
+ * revenue helpers attached flat: `track.priceShown()`, `track.lead()`,
228
+ * `track.converted()`, etc.
229
+ */
230
+ interface TrackFn extends RevenueTrackingApi {
231
+ (event: TrackInput): Promise<{
232
+ eventId: string;
233
+ }>;
234
+ }
144
235
  interface TrackingConfig {
145
236
  /** Events API V2 endpoint path. */
146
237
  endpointPath?: string;
@@ -180,10 +271,11 @@ interface TrackingClient {
180
271
  /**
181
272
  * Track an event using modern or legacy input shape.
182
273
  * Returns a deterministic event id immediately after enqueue.
274
+ *
275
+ * Also exposes the revenue helpers flat: `client.track.priceShown()`,
276
+ * `client.track.lead()`, `client.track.converted()`, etc.
183
277
  */
184
- track: (event: TrackInput) => Promise<{
185
- eventId: string;
186
- }>;
278
+ track: TrackFn;
187
279
  /**
188
280
  * Flush all currently buffered events.
189
281
  */
package/dist/index.d.ts CHANGED
@@ -103,7 +103,7 @@ interface WaniWaniProjectConfig {
103
103
  */
104
104
  declare function defineConfig(config: WaniWaniProjectConfig): WaniWaniProjectConfig;
105
105
 
106
- type EventType = "session.started" | "tool.called" | "quote.requested" | "quote.succeeded" | "quote.failed" | "link.clicked" | "purchase.completed" | "widget_render" | "widget_click" | "widget_link_click" | "widget_error" | "widget_scroll" | "widget_form_field" | "widget_form_submit" | "user.identified";
106
+ type EventType = "session.started" | "tool.called" | "quote.requested" | "quote.succeeded" | "quote.failed" | "link.clicked" | "purchase.completed" | "widget_render" | "widget_click" | "widget_link_click" | "widget_error" | "widget_scroll" | "widget_form_field" | "widget_form_submit" | "user.identified" | "price_shown" | "prices_compared" | "option_selected" | "lead" | "converted";
107
107
  interface ToolCalledProperties {
108
108
  name?: string;
109
109
  type?: "pricing" | "product_info" | "availability" | "support" | "other";
@@ -119,6 +119,34 @@ interface PurchaseCompletedProperties {
119
119
  amount?: number;
120
120
  currency?: string;
121
121
  }
122
+ interface PriceShownProperties {
123
+ amount: number;
124
+ currency: string;
125
+ itemId?: string;
126
+ label?: string;
127
+ }
128
+ interface ComparedPriceOption {
129
+ id: string;
130
+ amount: number;
131
+ currency: string;
132
+ }
133
+ interface PricesComparedProperties {
134
+ options: ComparedPriceOption[];
135
+ }
136
+ interface OptionSelectedProperties {
137
+ id: string;
138
+ amount: number;
139
+ currency: string;
140
+ }
141
+ interface LeadProperties {
142
+ source?: string;
143
+ }
144
+ interface ConvertedProperties {
145
+ amount: number;
146
+ currency: string;
147
+ /** When the conversion actually happened — for backdated off-platform sales. */
148
+ occurredAt?: string;
149
+ }
122
150
  interface TrackingContext {
123
151
  /**
124
152
  * MCP request metadata passed through to the API.
@@ -168,6 +196,21 @@ type TrackEvent = ({
168
196
  properties?: PurchaseCompletedProperties;
169
197
  } & BaseTrackEvent) | ({
170
198
  event: "user.identified";
199
+ } & BaseTrackEvent) | ({
200
+ event: "price_shown";
201
+ properties?: PriceShownProperties;
202
+ } & BaseTrackEvent) | ({
203
+ event: "prices_compared";
204
+ properties?: PricesComparedProperties;
205
+ } & BaseTrackEvent) | ({
206
+ event: "option_selected";
207
+ properties?: OptionSelectedProperties;
208
+ } & BaseTrackEvent) | ({
209
+ event: "lead";
210
+ properties?: LeadProperties;
211
+ } & BaseTrackEvent) | ({
212
+ event: "converted";
213
+ properties?: ConvertedProperties;
171
214
  } & BaseTrackEvent);
172
215
  /**
173
216
  * Legacy tracking shape supported for existing integrations.
@@ -187,6 +230,54 @@ interface LegacyTrackEvent extends TrackingContext {
187
230
  * Public track input accepted by `client.track()`.
188
231
  */
189
232
  type TrackInput = TrackEvent | LegacyTrackEvent;
233
+ interface RevenuePriceShownInput extends TrackingContext, PriceShownProperties {
234
+ }
235
+ interface RevenuePricesComparedInput extends TrackingContext, PricesComparedProperties {
236
+ }
237
+ interface RevenueOptionSelectedInput extends TrackingContext, OptionSelectedProperties {
238
+ }
239
+ /**
240
+ * Input for `track.lead()`. `source` is the lead's acquisition source
241
+ * (the `lead` event property, e.g. "newsletter") — on this helper it shadows
242
+ * the envelope `source` from the tracking context. To set a custom envelope
243
+ * source on a lead, use the generic `track({ event: "lead", … })`.
244
+ */
245
+ interface RevenueLeadInput extends TrackingContext, LeadProperties {
246
+ }
247
+ interface RevenueConvertedInput extends TrackingContext, ConvertedProperties {
248
+ }
249
+ /**
250
+ * Revenue-oriented helpers, flat on `client.track.*` (e.g.
251
+ * `client.track.priceShown()`, `client.track.converted()`). Decoupled from
252
+ * product primitives — each maps to a typed first-class revenue event.
253
+ */
254
+ interface RevenueTrackingApi {
255
+ priceShown: (input: RevenuePriceShownInput) => Promise<{
256
+ eventId: string;
257
+ }>;
258
+ pricesCompared: (input: RevenuePricesComparedInput) => Promise<{
259
+ eventId: string;
260
+ }>;
261
+ optionSelected: (input: RevenueOptionSelectedInput) => Promise<{
262
+ eventId: string;
263
+ }>;
264
+ lead: (input?: RevenueLeadInput) => Promise<{
265
+ eventId: string;
266
+ }>;
267
+ converted: (input: RevenueConvertedInput) => Promise<{
268
+ eventId: string;
269
+ }>;
270
+ }
271
+ /**
272
+ * `client.track` — callable for generic events (`track(event)`), with the
273
+ * revenue helpers attached flat: `track.priceShown()`, `track.lead()`,
274
+ * `track.converted()`, etc.
275
+ */
276
+ interface TrackFn extends RevenueTrackingApi {
277
+ (event: TrackInput): Promise<{
278
+ eventId: string;
279
+ }>;
280
+ }
190
281
  interface TrackingConfig {
191
282
  /** Events API V2 endpoint path. */
192
283
  endpointPath?: string;
@@ -226,10 +317,11 @@ interface TrackingClient {
226
317
  /**
227
318
  * Track an event using modern or legacy input shape.
228
319
  * Returns a deterministic event id immediately after enqueue.
320
+ *
321
+ * Also exposes the revenue helpers flat: `client.track.priceShown()`,
322
+ * `client.track.lead()`, `client.track.converted()`, etc.
229
323
  */
230
- track: (event: TrackInput) => Promise<{
231
- eventId: string;
232
- }>;
324
+ track: TrackFn;
233
325
  /**
234
326
  * Flush all currently buffered events.
235
327
  */
@@ -343,4 +435,4 @@ interface V2BatchResponse {
343
435
  */
344
436
  declare function waniwani(config?: WaniWaniConfig | WaniWaniProjectConfig): WaniWaniClient;
345
437
 
346
- export { type EventType, type KbClient, type KbIngestFile, type KbIngestResult, type KbSearchOptions, type KbSource, type LegacyTrackEvent, type LinkClickedProperties, type PurchaseCompletedProperties, type QuoteSucceededProperties, type ToolCalledProperties, type TrackEvent, type TrackInput, type TrackingConfig, type TrackingShutdownOptions, type TrackingShutdownResult, type V2BatchRejectedEvent, type V2BatchRequest, type V2BatchResponse, type V2CorrelationIds, type V2EnvelopeType, type V2EventEnvelope, type WaniWaniClient, type WaniWaniConfig, WaniWaniError, type WaniWaniProjectConfig, defineConfig, waniwani };
438
+ export { type ComparedPriceOption, type ConvertedProperties, type EventType, type KbClient, type KbIngestFile, type KbIngestResult, type KbSearchOptions, type KbSource, type LeadProperties, type LegacyTrackEvent, type LinkClickedProperties, type OptionSelectedProperties, type PriceShownProperties, type PricesComparedProperties, type PurchaseCompletedProperties, type QuoteSucceededProperties, type RevenueConvertedInput, type RevenueLeadInput, type RevenueOptionSelectedInput, type RevenuePriceShownInput, type RevenuePricesComparedInput, type RevenueTrackingApi, type ToolCalledProperties, type TrackEvent, type TrackFn, type TrackInput, type TrackingConfig, type TrackingShutdownOptions, type TrackingShutdownResult, type V2BatchRejectedEvent, type V2BatchRequest, type V2BatchResponse, type V2CorrelationIds, type V2EnvelopeType, type V2EventEnvelope, type WaniWaniClient, type WaniWaniConfig, WaniWaniError, type WaniWaniProjectConfig, defineConfig, waniwani };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var y=class extends Error{constructor(t,r){super(t);this.status=r;this.name="WaniWaniError"}};import{existsSync as j,readFileSync as V}from"fs";import{resolve as L}from"path";var O="waniwani.json",g;function S(){if(g!==void 0)return g;try{let e=L(process.cwd(),O);if(!j(e))return g=null,null;let n=V(e,"utf-8");return g=JSON.parse(n),g}catch{return g=null,null}}var k="__waniwani_config__";function K(e){return globalThis[k]=e,e}function R(){return globalThis[k]}var N="@waniwani/sdk";function b(e){let{apiUrl:n,apiKey:t}=e;function r(){if(!t)throw new Error("WANIWANI_API_KEY is not set");return t}async function i(s,o,a){let u=r(),m=`${n.replace(/\/$/,"")}${o}`,p={Authorization:`Bearer ${u}`,"X-WaniWani-SDK":N},h={method:s,headers:p};a!==void 0&&(p["Content-Type"]="application/json",h.body=JSON.stringify(a));let d=await fetch(m,h);if(!d.ok){let U=await d.text().catch(()=>"");throw new y(U||`KB API error: HTTP ${d.status}`,d.status)}return(await d.json()).data}return{async ingest(s){return i("POST","/api/mcp/kb/ingest",{files:s})},async search(s,o){return i("POST","/api/mcp/kb/search",{query:s,...o})},async sources(){return i("GET","/api/mcp/kb/sources")}}}function v(e,n){for(let t of n){let r=e[t];if(typeof r=="string"&&r.length>0)return r}}var q=["waniwani/sessionId","openai/sessionId","openai/session","sessionId","conversationId","mcp-session-id"],z=["waniwani/requestId","openai/requestId","requestId","mcp/requestId"],Y=["waniwani/traceId","openai/traceId","traceId","mcp/traceId","openai/requestId","requestId"],$=["waniwani/userId","openai/userId","externalUserId","userId","actorId"],H=["correlationId","openai/requestId"];function x(e){return e?v(e,q):void 0}function _(e){return e?v(e,z):void 0}function C(e){return e?v(e,Y):void 0}function M(e){return e?v(e,$):void 0}function A(e){return e?v(e,H):void 0}var X=[{key:"openai/sessionId",source:"chatgpt"},{key:"openai/session",source:"chatgpt"}],G=[{needle:"claude",source:"claude"}];function D(e,n){if(e){let r=e["waniwani/source"];if(typeof r=="string"&&r.length>0)return r;for(let{key:i,source:s}of X){let o=e[i];if(typeof o=="string"&&o.length>0)return s}}let t=n?.name;if(typeof t=="string"&&t.length>0){let r=t.toLowerCase();for(let{needle:i,source:s}of G)if(r.includes(i))return s}}var J="@waniwani/sdk";function E(e,n={}){let t=n.now??(()=>new Date),r=n.generateId??W,i=ee(e),s=T(e.meta),o=T(e.metadata),a=te(e,s),u=c(e.eventId)??r(),m=ne(e.timestamp,t),p=c(e.source)??D(s)??n.source??J,h=I(e)?{...e}:void 0,d={...o};return Object.keys(s).length>0&&(d.meta=s),h&&(d.rawLegacy=h),{id:u,type:"mcp.event",name:i,source:p,timestamp:m,correlation:a,properties:Z(e,i),metadata:d,rawLegacy:h}}function W(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?`evt_${crypto.randomUUID()}`:`evt_${Math.random().toString(36).slice(2,10)}_${Date.now().toString(36)}`}function Z(e,n){if(!I(e))return T(e.properties);let t=Q(e,n),r=T(e.properties);return{...t,...r}}function Q(e,n){switch(n){case"tool.called":{let t={};return c(e.toolName)&&(t.name=e.toolName),c(e.toolType)&&(t.type=e.toolType),t}case"quote.succeeded":{let t={};return typeof e.quoteAmount=="number"&&(t.amount=e.quoteAmount),c(e.quoteCurrency)&&(t.currency=e.quoteCurrency),t}case"link.clicked":{let t={};return c(e.linkUrl)&&(t.url=e.linkUrl),t}case"purchase.completed":{let t={};return typeof e.purchaseAmount=="number"&&(t.amount=e.purchaseAmount),c(e.purchaseCurrency)&&(t.currency=e.purchaseCurrency),t}default:return{}}}function ee(e){return I(e)?e.eventType:e.event}function te(e,n){let t=c(e.requestId)??_(n),r=c(e.sessionId)??x(n),i=c(e.traceId)??C(n),s=c(e.externalUserId)??M(n),o=c(e.correlationId)??A(n)??t,a={};return r&&(a.sessionId=r),i&&(a.traceId=i),t&&(a.requestId=t),o&&(a.correlationId=o),s&&(a.externalUserId=s),a}function ne(e,n){if(e instanceof Date)return e.toISOString();if(typeof e=="string"){let t=new Date(e);if(!Number.isNaN(t.getTime()))return t.toISOString()}return n().toISOString()}function T(e){return!e||typeof e!="object"||Array.isArray(e)?{}:e}function c(e){if(typeof e=="string"&&e.trim().length!==0)return e}function I(e){return"eventType"in e}var re="/api/mcp/events/v2/batch";var P="@waniwani/sdk",ie=new Set([401,403]),se=new Set([408,425,429,500,502,503,504]);function B(e){return new w(e)}var w=class{endpointUrl;flushIntervalMs;maxBatchSize;maxBufferSize;maxRetries;retryBaseDelayMs;retryMaxDelayMs;shutdownTimeoutMs;sdkVersion;fetchFn;logger;now;sleep;apiKey;buffer=[];flushTimer;flushScheduled=!1;flushScheduledTimer;flushInFlight;inFlightCount=0;isStopped=!1;isShuttingDown=!1;constructor(n){this.endpointUrl=ce(n.apiUrl,n.endpointPath??re),this.flushIntervalMs=n.flushIntervalMs??1e3,this.maxBatchSize=n.maxBatchSize??20,this.maxBufferSize=n.maxBufferSize??1e3,this.maxRetries=n.maxRetries??3,this.retryBaseDelayMs=n.retryBaseDelayMs??200,this.retryMaxDelayMs=n.retryMaxDelayMs??2e3,this.shutdownTimeoutMs=n.shutdownTimeoutMs??2e3,this.fetchFn=n.fetchFn??fetch,this.logger=n.logger??console,this.now=n.now??(()=>new Date),this.sleep=n.sleep??(t=>new Promise(r=>setTimeout(r,t))),this.apiKey=n.apiKey,this.sdkVersion=n.sdkVersion,this.flushIntervalMs>0&&(this.flushTimer=setInterval(()=>{this.flush()},this.flushIntervalMs))}enqueue(n){if(this.isStopped||this.isShuttingDown){this.logger.warn("[WaniWani] Tracking transport is stopped, dropping event %s",n.id);return}if(this.buffer.length>=this.maxBufferSize){let t=this.buffer.length-this.maxBufferSize+1;this.buffer.splice(0,t),this.logger.warn("[WaniWani] Tracking buffer overflow, dropped %d oldest event(s)",t)}if(this.buffer.push(n),this.buffer.length>=this.maxBatchSize){this.flush();return}this.scheduleMicroFlush()}pendingEvents(){return this.buffer.length+this.inFlightCount}async flush(){return this.flushInFlight?this.flushInFlight:(this.flushInFlight=this.flushLoop().finally(()=>{this.flushInFlight=void 0}),this.flushInFlight)}async shutdown(n){this.isShuttingDown=!0,this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=void 0),this.flushScheduledTimer&&(clearTimeout(this.flushScheduledTimer),this.flushScheduledTimer=void 0,this.flushScheduled=!1);let t=n?.timeoutMs??this.shutdownTimeoutMs,r=this.flush();if(!Number.isFinite(t)||t<=0)return await r,this.isStopped=!0,{timedOut:!1,pendingEvents:this.pendingEvents()};let i=Symbol("shutdown-timeout");return await Promise.race([r.then(()=>"flushed"),this.sleep(t).then(()=>i)])===i?(this.isStopped=!0,{timedOut:!0,pendingEvents:this.pendingEvents()}):(this.isStopped=!0,{timedOut:!1,pendingEvents:this.pendingEvents()})}scheduleMicroFlush(){this.flushScheduled||(this.flushScheduled=!0,this.flushScheduledTimer=setTimeout(()=>{this.flushScheduledTimer=void 0,this.flushScheduled=!1,this.flush()},0))}async flushLoop(){for(;this.buffer.length>0&&!this.isStopped;){let n=this.buffer.splice(0,this.maxBatchSize);await this.sendBatchWithRetry(n)}}async sendBatchWithRetry(n){let t=0,r=n;for(;r.length>0&&!this.isStopped;){this.inFlightCount=r.length;let i=await this.sendBatchOnce(r);switch(this.inFlightCount=0,i.kind){case"success":return;case"auth":this.stopTransportForAuthFailure(i.status,r.length);return;case"permanent":this.logger.error("[WaniWani] Dropping %d event(s) after permanent failure: %s",r.length,i.reason);return;case"retryable":if(t>=this.maxRetries){this.logger.error("[WaniWani] Dropping %d event(s) after retry exhaustion: %s",r.length,i.reason);return}await this.sleep(this.backoffDelayMs(t)),t+=1;continue;case"partial":if(i.permanent.length>0&&this.logger.error("[WaniWani] Dropping %d event(s) rejected as permanent",i.permanent.length),i.retryable.length===0)return;if(t>=this.maxRetries){this.logger.error("[WaniWani] Dropping %d retryable event(s) after retry exhaustion",i.retryable.length);return}r=i.retryable,await this.sleep(this.backoffDelayMs(t)),t+=1;continue}}}async sendBatchOnce(n){let t;try{t=await this.fetchFn(this.endpointUrl,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,"X-WaniWani-SDK":P},body:JSON.stringify(this.makeBatchRequest(n))})}catch(s){return{kind:"retryable",reason:ue(s)}}if(ie.has(t.status))return{kind:"auth",status:t.status};if(se.has(t.status))return{kind:"retryable",reason:`HTTP ${t.status}`};if(!t.ok)return{kind:"permanent",reason:`HTTP ${t.status}`};let r=await ae(t);if(!r?.rejected||r.rejected.length===0)return{kind:"success"};let i=this.classifyRejectedEvents(n,r.rejected);return i.retryable.length===0&&i.permanent.length===0?{kind:"success"}:{kind:"partial",retryable:i.retryable,permanent:i.permanent}}makeBatchRequest(n){return{sentAt:this.now().toISOString(),source:{sdk:P,version:this.sdkVersion??"0.0.0"},events:n}}classifyRejectedEvents(n,t){let r=new Map(n.map(o=>[o.id,o])),i=[],s=[];for(let o of t){let a=r.get(o.eventId);if(a){if(oe(o)){i.push(a);continue}s.push(a)}}return{retryable:i,permanent:s}}backoffDelayMs(n){let t=this.retryBaseDelayMs*2**n;return Math.min(t,this.retryMaxDelayMs)}stopTransportForAuthFailure(n,t){this.isStopped=!0;let r=this.buffer.length;this.buffer.splice(0,r),this.logger.error("[WaniWani] Auth failure (HTTP %d). Stopping tracking transport and dropping %d queued event(s)",n,t+r)}};function oe(e){if(e.retryable===!0)return!0;let n=e.code.toLowerCase();return n.includes("timeout")||n.includes("temporary")||n.includes("unavailable")||n.includes("rate_limit")||n.includes("transient")||n.includes("server")}async function ae(e){let n=await e.text();if(n)try{return JSON.parse(n)}catch{return}}function ce(e,n){let t=e.endsWith("/")?e:`${e}/`,r=n.startsWith("/")?n.slice(1):n;return`${t}${r}`}function ue(e){return e instanceof Error?e.message:String(e)}function F(e){let{apiUrl:n,apiKey:t,tracking:r}=e;function i(){if(!t)throw new Error("WANIWANI_API_KEY is not set");return t}let s=t?B({apiUrl:n,apiKey:t,endpointPath:r.endpointPath,flushIntervalMs:r.flushIntervalMs,maxBatchSize:r.maxBatchSize,maxBufferSize:r.maxBufferSize,maxRetries:r.maxRetries,retryBaseDelayMs:r.retryBaseDelayMs,retryMaxDelayMs:r.retryMaxDelayMs,shutdownTimeoutMs:r.shutdownTimeoutMs}):void 0,o={async identify(a,u,m){i();let p=E({event:"user.identified",externalUserId:a,properties:u,meta:m});return s?.enqueue(p),{eventId:p.id}},async track(a){i();let u=E(a);return s?.enqueue(u),{eventId:u.id}},async flush(){i(),await s?.flush()},async shutdown(a){return i(),await s?.shutdown({timeoutMs:a?.timeoutMs??r.shutdownTimeoutMs})??{timedOut:!1,pendingEvents:0}}};return s&&de(o,r.shutdownTimeoutMs),o}function de(e,n){if(typeof process>"u"||typeof process.once!="function"||typeof process.on!="function")return;let t=()=>{e.shutdown({timeoutMs:n})};process.once("beforeExit",t),process.once("SIGINT",t),process.once("SIGTERM",t)}function le(e){let t=e??S()??R(),r=t?.apiUrl??"https://app.waniwani.ai",i=t?.apiKey??process.env.WANIWANI_API_KEY,s={endpointPath:t?.tracking?.endpointPath??"/api/mcp/events/v2/batch",flushIntervalMs:t?.tracking?.flushIntervalMs??1e3,maxBatchSize:t?.tracking?.maxBatchSize??20,maxBufferSize:t?.tracking?.maxBufferSize??1e3,maxRetries:t?.tracking?.maxRetries??3,retryBaseDelayMs:t?.tracking?.retryBaseDelayMs??200,retryMaxDelayMs:t?.tracking?.retryMaxDelayMs??2e3,shutdownTimeoutMs:t?.tracking?.shutdownTimeoutMs??2e3},o={apiUrl:r,apiKey:i,tracking:s},a=F(o),u=b(o);return{...a,kb:u,_config:o}}export{y as WaniWaniError,K as defineConfig,le as waniwani};
1
+ var y=class extends Error{constructor(t,r){super(t);this.status=r;this.name="WaniWaniError"}};import{existsSync as L,readFileSync as V}from"fs";import{resolve as K}from"path";var N="waniwani.json",m;function k(){if(m!==void 0)return m;try{let e=K(process.cwd(),N);if(!L(e))return m=null,null;let n=V(e,"utf-8");return m=JSON.parse(n),m}catch{return m=null,null}}var R="__waniwani_config__";function q(e){return globalThis[R]=e,e}function x(){return globalThis[R]}var z="@waniwani/sdk";function b(e){let{apiUrl:n,apiKey:t}=e;function r(){if(!t)throw new Error("WANIWANI_API_KEY is not set");return t}async function i(s,o,a){let h=r(),g=`${n.replace(/\/$/,"")}${o}`,u={Authorization:`Bearer ${h}`,"X-WaniWani-SDK":z},c={method:s,headers:u};a!==void 0&&(u["Content-Type"]="application/json",c.body=JSON.stringify(a));let p=await fetch(g,c);if(!p.ok){let j=await p.text().catch(()=>"");throw new y(j||`KB API error: HTTP ${p.status}`,p.status)}return(await p.json()).data}return{async ingest(s){return i("POST","/api/mcp/kb/ingest",{files:s})},async search(s,o){return i("POST","/api/mcp/kb/search",{query:s,...o})},async sources(){return i("GET","/api/mcp/kb/sources")}}}function v(e,n){for(let t of n){let r=e[t];if(typeof r=="string"&&r.length>0)return r}}var Y=["waniwani/sessionId","openai/sessionId","openai/session","sessionId","conversationId","mcp-session-id"],$=["waniwani/requestId","openai/requestId","requestId","mcp/requestId"],H=["waniwani/traceId","openai/traceId","traceId","mcp/traceId","openai/requestId","requestId"],X=["waniwani/userId","openai/userId","externalUserId","userId","actorId"],G=["correlationId","openai/requestId"];function C(e){return e?v(e,Y):void 0}function _(e){return e?v(e,$):void 0}function P(e){return e?v(e,H):void 0}function M(e){return e?v(e,X):void 0}function A(e){return e?v(e,G):void 0}var J=[{key:"openai/sessionId",source:"chatgpt"},{key:"openai/session",source:"chatgpt"}],Z=[{needle:"claude",source:"claude"}];function D(e,n){if(e){let r=e["waniwani/source"];if(typeof r=="string"&&r.length>0)return r;for(let{key:i,source:s}of J){let o=e[i];if(typeof o=="string"&&o.length>0)return s}}let t=n?.name;if(typeof t=="string"&&t.length>0){let r=t.toLowerCase();for(let{needle:i,source:s}of Z)if(r.includes(i))return s}}var Q="@waniwani/sdk";function I(e,n={}){let t=n.now??(()=>new Date),r=n.generateId??W,i=ne(e),s=T(e.meta),o=T(e.metadata),a=re(e,s),h=d(e.eventId)??r(),g=ie(e.timestamp,t),u=d(e.source)??D(s)??n.source??Q,c=w(e)?{...e}:void 0,p={...o};return Object.keys(s).length>0&&(p.meta=s),c&&(p.rawLegacy=c),{id:h,type:"mcp.event",name:i,source:u,timestamp:g,correlation:a,properties:ee(e,i),metadata:p,rawLegacy:c}}function W(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?`evt_${crypto.randomUUID()}`:`evt_${Math.random().toString(36).slice(2,10)}_${Date.now().toString(36)}`}function ee(e,n){if(!w(e))return T(e.properties);let t=te(e,n),r=T(e.properties);return{...t,...r}}function te(e,n){switch(n){case"tool.called":{let t={};return d(e.toolName)&&(t.name=e.toolName),d(e.toolType)&&(t.type=e.toolType),t}case"quote.succeeded":{let t={};return typeof e.quoteAmount=="number"&&(t.amount=e.quoteAmount),d(e.quoteCurrency)&&(t.currency=e.quoteCurrency),t}case"link.clicked":{let t={};return d(e.linkUrl)&&(t.url=e.linkUrl),t}case"purchase.completed":{let t={};return typeof e.purchaseAmount=="number"&&(t.amount=e.purchaseAmount),d(e.purchaseCurrency)&&(t.currency=e.purchaseCurrency),t}default:return{}}}function ne(e){return w(e)?e.eventType:e.event}function re(e,n){let t=d(e.requestId)??_(n),r=d(e.sessionId)??C(n),i=d(e.traceId)??P(n),s=d(e.externalUserId)??M(n),o=d(e.correlationId)??A(n)??t,a={};return r&&(a.sessionId=r),i&&(a.traceId=i),t&&(a.requestId=t),o&&(a.correlationId=o),s&&(a.externalUserId=s),a}function ie(e,n){if(e instanceof Date)return e.toISOString();if(typeof e=="string"){let t=new Date(e);if(!Number.isNaN(t.getTime()))return t.toISOString()}return n().toISOString()}function T(e){return!e||typeof e!="object"||Array.isArray(e)?{}:e}function d(e){if(typeof e=="string"&&e.trim().length!==0)return e}function w(e){return"eventType"in e}function B(e){return{priceShown:({amount:n,currency:t,itemId:r,label:i,...s})=>e({event:"price_shown",properties:{amount:n,currency:t,itemId:r,label:i},...s}),pricesCompared:({options:n,...t})=>e({event:"prices_compared",properties:{options:n},...t}),optionSelected:({id:n,amount:t,currency:r,...i})=>e({event:"option_selected",properties:{id:n,amount:t,currency:r},...i}),lead:n=>{let{source:t,...r}=n??{};return e({event:"lead",properties:{source:t},...r})},converted:({amount:n,currency:t,occurredAt:r,...i})=>e({event:"converted",properties:{amount:n,currency:t,occurredAt:r},...i})}}var se="/api/mcp/events/v2/batch";var F="@waniwani/sdk",oe=new Set([401,403]),ae=new Set([408,425,429,500,502,503,504]);function O(e){return new S(e)}var S=class{endpointUrl;flushIntervalMs;maxBatchSize;maxBufferSize;maxRetries;retryBaseDelayMs;retryMaxDelayMs;shutdownTimeoutMs;sdkVersion;fetchFn;logger;now;sleep;apiKey;buffer=[];flushTimer;flushScheduled=!1;flushScheduledTimer;flushInFlight;inFlightCount=0;isStopped=!1;isShuttingDown=!1;constructor(n){this.endpointUrl=de(n.apiUrl,n.endpointPath??se),this.flushIntervalMs=n.flushIntervalMs??1e3,this.maxBatchSize=n.maxBatchSize??20,this.maxBufferSize=n.maxBufferSize??1e3,this.maxRetries=n.maxRetries??3,this.retryBaseDelayMs=n.retryBaseDelayMs??200,this.retryMaxDelayMs=n.retryMaxDelayMs??2e3,this.shutdownTimeoutMs=n.shutdownTimeoutMs??2e3,this.fetchFn=n.fetchFn??fetch,this.logger=n.logger??console,this.now=n.now??(()=>new Date),this.sleep=n.sleep??(t=>new Promise(r=>setTimeout(r,t))),this.apiKey=n.apiKey,this.sdkVersion=n.sdkVersion,this.flushIntervalMs>0&&(this.flushTimer=setInterval(()=>{this.flush()},this.flushIntervalMs))}enqueue(n){if(this.isStopped||this.isShuttingDown){this.logger.warn("[WaniWani] Tracking transport is stopped, dropping event %s",n.id);return}if(this.buffer.length>=this.maxBufferSize){let t=this.buffer.length-this.maxBufferSize+1;this.buffer.splice(0,t),this.logger.warn("[WaniWani] Tracking buffer overflow, dropped %d oldest event(s)",t)}if(this.buffer.push(n),this.buffer.length>=this.maxBatchSize){this.flush();return}this.scheduleMicroFlush()}pendingEvents(){return this.buffer.length+this.inFlightCount}async flush(){return this.flushInFlight?this.flushInFlight:(this.flushInFlight=this.flushLoop().finally(()=>{this.flushInFlight=void 0}),this.flushInFlight)}async shutdown(n){this.isShuttingDown=!0,this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=void 0),this.flushScheduledTimer&&(clearTimeout(this.flushScheduledTimer),this.flushScheduledTimer=void 0,this.flushScheduled=!1);let t=n?.timeoutMs??this.shutdownTimeoutMs,r=this.flush();if(!Number.isFinite(t)||t<=0)return await r,this.isStopped=!0,{timedOut:!1,pendingEvents:this.pendingEvents()};let i=Symbol("shutdown-timeout");return await Promise.race([r.then(()=>"flushed"),this.sleep(t).then(()=>i)])===i?(this.isStopped=!0,{timedOut:!0,pendingEvents:this.pendingEvents()}):(this.isStopped=!0,{timedOut:!1,pendingEvents:this.pendingEvents()})}scheduleMicroFlush(){this.flushScheduled||(this.flushScheduled=!0,this.flushScheduledTimer=setTimeout(()=>{this.flushScheduledTimer=void 0,this.flushScheduled=!1,this.flush()},0))}async flushLoop(){for(;this.buffer.length>0&&!this.isStopped;){let n=this.buffer.splice(0,this.maxBatchSize);await this.sendBatchWithRetry(n)}}async sendBatchWithRetry(n){let t=0,r=n;for(;r.length>0&&!this.isStopped;){this.inFlightCount=r.length;let i=await this.sendBatchOnce(r);switch(this.inFlightCount=0,i.kind){case"success":return;case"auth":this.stopTransportForAuthFailure(i.status,r.length);return;case"permanent":this.logger.error("[WaniWani] Dropping %d event(s) after permanent failure: %s",r.length,i.reason);return;case"retryable":if(t>=this.maxRetries){this.logger.error("[WaniWani] Dropping %d event(s) after retry exhaustion: %s",r.length,i.reason);return}await this.sleep(this.backoffDelayMs(t)),t+=1;continue;case"partial":if(i.permanent.length>0&&this.logger.error("[WaniWani] Dropping %d event(s) rejected as permanent",i.permanent.length),i.retryable.length===0)return;if(t>=this.maxRetries){this.logger.error("[WaniWani] Dropping %d retryable event(s) after retry exhaustion",i.retryable.length);return}r=i.retryable,await this.sleep(this.backoffDelayMs(t)),t+=1;continue}}}async sendBatchOnce(n){let t;try{t=await this.fetchFn(this.endpointUrl,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,"X-WaniWani-SDK":F},body:JSON.stringify(this.makeBatchRequest(n))})}catch(s){return{kind:"retryable",reason:pe(s)}}if(oe.has(t.status))return{kind:"auth",status:t.status};if(ae.has(t.status))return{kind:"retryable",reason:`HTTP ${t.status}`};if(!t.ok)return{kind:"permanent",reason:`HTTP ${t.status}`};let r=await ue(t);if(!r?.rejected||r.rejected.length===0)return{kind:"success"};let i=this.classifyRejectedEvents(n,r.rejected);return i.retryable.length===0&&i.permanent.length===0?{kind:"success"}:{kind:"partial",retryable:i.retryable,permanent:i.permanent}}makeBatchRequest(n){return{sentAt:this.now().toISOString(),source:{sdk:F,version:this.sdkVersion??"0.0.0"},events:n}}classifyRejectedEvents(n,t){let r=new Map(n.map(o=>[o.id,o])),i=[],s=[];for(let o of t){let a=r.get(o.eventId);if(a){if(ce(o)){i.push(a);continue}s.push(a)}}return{retryable:i,permanent:s}}backoffDelayMs(n){let t=this.retryBaseDelayMs*2**n;return Math.min(t,this.retryMaxDelayMs)}stopTransportForAuthFailure(n,t){this.isStopped=!0;let r=this.buffer.length;this.buffer.splice(0,r),this.logger.error("[WaniWani] Auth failure (HTTP %d). Stopping tracking transport and dropping %d queued event(s)",n,t+r)}};function ce(e){if(e.retryable===!0)return!0;let n=e.code.toLowerCase();return n.includes("timeout")||n.includes("temporary")||n.includes("unavailable")||n.includes("rate_limit")||n.includes("transient")||n.includes("server")}async function ue(e){let n=await e.text();if(n)try{return JSON.parse(n)}catch{return}}function de(e,n){let t=e.endsWith("/")?e:`${e}/`,r=n.startsWith("/")?n.slice(1):n;return`${t}${r}`}function pe(e){return e instanceof Error?e.message:String(e)}function U(e){let{apiUrl:n,apiKey:t,tracking:r}=e;function i(){if(!t)throw new Error("WANIWANI_API_KEY is not set");return t}let s=t?O({apiUrl:n,apiKey:t,endpointPath:r.endpointPath,flushIntervalMs:r.flushIntervalMs,maxBatchSize:r.maxBatchSize,maxBufferSize:r.maxBufferSize,maxRetries:r.maxRetries,retryBaseDelayMs:r.retryBaseDelayMs,retryMaxDelayMs:r.retryMaxDelayMs,shutdownTimeoutMs:r.shutdownTimeoutMs}):void 0;function o(u){i();let c=I(u);return!c.correlation.sessionId&&!c.correlation.externalUserId&&console.warn(`[waniwani] event "${c.name}" has no sessionId or externalUserId; the ingest API requires one and will reject it.`),s?.enqueue(c),{eventId:c.id}}let a=async u=>o(u),h=Object.assign(a,B(a)),g={async identify(u,c,p){i();let E=I({event:"user.identified",externalUserId:u,properties:c,meta:p});return s?.enqueue(E),{eventId:E.id}},track:h,async flush(){i(),await s?.flush()},async shutdown(u){return i(),await s?.shutdown({timeoutMs:u?.timeoutMs??r.shutdownTimeoutMs})??{timedOut:!1,pendingEvents:0}}};return s&&le(g,r.shutdownTimeoutMs),g}function le(e,n){if(typeof process>"u"||typeof process.once!="function"||typeof process.on!="function")return;let t=()=>{e.shutdown({timeoutMs:n})};process.once("beforeExit",t),process.once("SIGINT",t),process.once("SIGTERM",t)}function fe(e){let t=e??k()??x(),r=t?.apiUrl??"https://app.waniwani.ai",i=t?.apiKey??process.env.WANIWANI_API_KEY,s={endpointPath:t?.tracking?.endpointPath??"/api/mcp/events/v2/batch",flushIntervalMs:t?.tracking?.flushIntervalMs??1e3,maxBatchSize:t?.tracking?.maxBatchSize??20,maxBufferSize:t?.tracking?.maxBufferSize??1e3,maxRetries:t?.tracking?.maxRetries??3,retryBaseDelayMs:t?.tracking?.retryBaseDelayMs??200,retryMaxDelayMs:t?.tracking?.retryMaxDelayMs??2e3,shutdownTimeoutMs:t?.tracking?.shutdownTimeoutMs??2e3},o={apiUrl:r,apiKey:i,tracking:s},a=U(o),h=b(o);return{...a,kb:h,_config:o}}export{y as WaniWaniError,q as defineConfig,fe as waniwani};
2
2
  //# sourceMappingURL=index.js.map