@waniwani/sdk 0.18.0 → 0.19.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.
@@ -68,7 +68,7 @@ interface KbClient {
68
68
  * first-class names at runtime (the widget transport passes these through
69
69
  * verbatim instead of namespacing them as custom widget events).
70
70
  */
71
- declare const EVENT_TYPES: readonly ["session.started", "page.viewed", "tool.called", "quote.requested", "quote.succeeded", "quote.failed", "link.clicked", "purchase.completed", "widget_render", "user.identified", "price_shown", "prices_compared", "option_selected", "lead_qualified", "converted"];
71
+ declare const EVENT_TYPES: readonly ["session.started", "page.viewed", "tool.called", "link.clicked", "widget_render", "user.identified", "price_shown", "prices_compared", "option_selected", "lead_qualified", "converted"];
72
72
  type EventType = (typeof EVENT_TYPES)[number];
73
73
  /**
74
74
  * Properties for `page.viewed` — emitted once when the chat widget initializes
@@ -97,17 +97,9 @@ interface ToolCalledProperties {
97
97
  /** Retrieval traces for kb.search() calls made inside this tool handler. */
98
98
  kbSearch?: KbSearchTrace[];
99
99
  }
100
- interface QuoteSucceededProperties {
101
- amount?: number;
102
- currency?: string;
103
- }
104
100
  interface LinkClickedProperties {
105
101
  url?: string;
106
102
  }
107
- interface PurchaseCompletedProperties {
108
- amount?: number;
109
- currency?: string;
110
- }
111
103
  interface PriceShownProperties {
112
104
  amount: number;
113
105
  currency: string;
@@ -194,19 +186,9 @@ type TrackEvent = ({
194
186
  } & BaseTrackEvent) | ({
195
187
  event: "tool.called";
196
188
  properties?: ToolCalledProperties;
197
- } & BaseTrackEvent) | ({
198
- event: "quote.requested";
199
- } & BaseTrackEvent) | ({
200
- event: "quote.succeeded";
201
- properties?: QuoteSucceededProperties;
202
- } & BaseTrackEvent) | ({
203
- event: "quote.failed";
204
189
  } & BaseTrackEvent) | ({
205
190
  event: "link.clicked";
206
191
  properties?: LinkClickedProperties;
207
- } & BaseTrackEvent) | ({
208
- event: "purchase.completed";
209
- properties?: PurchaseCompletedProperties;
210
192
  } & BaseTrackEvent) | ({
211
193
  event: "user.identified";
212
194
  } & BaseTrackEvent) | ({
@@ -235,11 +217,7 @@ interface LegacyTrackEvent extends TrackingContext {
235
217
  properties?: Record<string, unknown>;
236
218
  toolName?: string;
237
219
  toolType?: ToolCalledProperties["type"];
238
- quoteAmount?: number;
239
- quoteCurrency?: string;
240
220
  linkUrl?: string;
241
- purchaseAmount?: number;
242
- purchaseCurrency?: string;
243
221
  }
244
222
  /**
245
223
  * Public track input accepted by `client.track()`.
package/dist/index.d.ts CHANGED
@@ -115,7 +115,7 @@ declare function defineConfig(config: WaniWaniProjectConfig): WaniWaniProjectCon
115
115
  * first-class names at runtime (the widget transport passes these through
116
116
  * verbatim instead of namespacing them as custom widget events).
117
117
  */
118
- declare const EVENT_TYPES: readonly ["session.started", "page.viewed", "tool.called", "quote.requested", "quote.succeeded", "quote.failed", "link.clicked", "purchase.completed", "widget_render", "user.identified", "price_shown", "prices_compared", "option_selected", "lead_qualified", "converted"];
118
+ declare const EVENT_TYPES: readonly ["session.started", "page.viewed", "tool.called", "link.clicked", "widget_render", "user.identified", "price_shown", "prices_compared", "option_selected", "lead_qualified", "converted"];
119
119
  type EventType = (typeof EVENT_TYPES)[number];
120
120
  /**
121
121
  * Properties for `page.viewed` — emitted once when the chat widget initializes
@@ -144,17 +144,9 @@ interface ToolCalledProperties {
144
144
  /** Retrieval traces for kb.search() calls made inside this tool handler. */
145
145
  kbSearch?: KbSearchTrace[];
146
146
  }
147
- interface QuoteSucceededProperties {
148
- amount?: number;
149
- currency?: string;
150
- }
151
147
  interface LinkClickedProperties {
152
148
  url?: string;
153
149
  }
154
- interface PurchaseCompletedProperties {
155
- amount?: number;
156
- currency?: string;
157
- }
158
150
  interface PriceShownProperties {
159
151
  amount: number;
160
152
  currency: string;
@@ -241,19 +233,9 @@ type TrackEvent = ({
241
233
  } & BaseTrackEvent) | ({
242
234
  event: "tool.called";
243
235
  properties?: ToolCalledProperties;
244
- } & BaseTrackEvent) | ({
245
- event: "quote.requested";
246
- } & BaseTrackEvent) | ({
247
- event: "quote.succeeded";
248
- properties?: QuoteSucceededProperties;
249
- } & BaseTrackEvent) | ({
250
- event: "quote.failed";
251
236
  } & BaseTrackEvent) | ({
252
237
  event: "link.clicked";
253
238
  properties?: LinkClickedProperties;
254
- } & BaseTrackEvent) | ({
255
- event: "purchase.completed";
256
- properties?: PurchaseCompletedProperties;
257
239
  } & BaseTrackEvent) | ({
258
240
  event: "user.identified";
259
241
  } & BaseTrackEvent) | ({
@@ -282,11 +264,7 @@ interface LegacyTrackEvent extends TrackingContext {
282
264
  properties?: Record<string, unknown>;
283
265
  toolName?: string;
284
266
  toolType?: ToolCalledProperties["type"];
285
- quoteAmount?: number;
286
- quoteCurrency?: string;
287
267
  linkUrl?: string;
288
- purchaseAmount?: number;
289
- purchaseCurrency?: string;
290
268
  }
291
269
  /**
292
270
  * Public track input accepted by `client.track()`.
@@ -569,4 +547,4 @@ interface V2BatchResponse {
569
547
  */
570
548
  declare function waniwani(config?: WaniWaniConfig | WaniWaniProjectConfig): WaniWaniClient;
571
549
 
572
- export { type ComparedPriceOption, type ConvertedProperties, EVENT_TYPES, type EventType, type FrontendClientOptions, type FrontendIdentity, type FrontendTrackingClient, type KbClient, type KbIngestFile, type KbIngestResult, type KbSearchOptions, type KbSource, type LeadQualifiedProperties, type LegacyTrackEvent, type LinkClickedProperties, type OptionSelectedProperties, type PriceShownProperties, type PricesComparedProperties, type PurchaseCompletedProperties, type QuoteSucceededProperties, type RevenueConvertedInput, type RevenueLeadQualifiedInput, 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, createFrontendClient, defineConfig, waniwani };
550
+ export { type ComparedPriceOption, type ConvertedProperties, EVENT_TYPES, type EventType, type FrontendClientOptions, type FrontendIdentity, type FrontendTrackingClient, type KbClient, type KbIngestFile, type KbIngestResult, type KbSearchOptions, type KbSource, type LeadQualifiedProperties, type LegacyTrackEvent, type LinkClickedProperties, type OptionSelectedProperties, type PriceShownProperties, type PricesComparedProperties, type RevenueConvertedInput, type RevenueLeadQualifiedInput, 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, createFrontendClient, defineConfig, waniwani };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var T=class extends Error{constructor(n,r){super(n);this.status=r;this.name="WaniWaniError"}};import{existsSync as Y,readFileSync as z}from"fs";import{resolve as $}from"path";var H="waniwani.json",m;function P(){if(m!==void 0)return m;try{let e=$(process.cwd(),H);if(!Y(e))return m=null,null;let t=z(e,"utf-8");return m=JSON.parse(t),m}catch{return m=null,null}}var b="__waniwani_config__";function Q(e){return globalThis[b]=e,e}function C(){return globalThis[b]}var _=["session.started","page.viewed","tool.called","quote.requested","quote.succeeded","quote.failed","link.clicked","purchase.completed","widget_render","user.identified","price_shown","prices_compared","option_selected","lead_qualified","converted"];function v(e,t){for(let n of t){let r=e[n];if(typeof r=="string"&&r.length>0)return r}}var X=["waniwani/sessionId","openai/sessionId","openai/session","sessionId","conversationId","mcp-session-id"],G=["waniwani/requestId","openai/requestId","requestId","mcp/requestId"],J=["waniwani/traceId","openai/traceId","traceId","mcp/traceId","openai/requestId","requestId"],Z=["waniwani/userId","openai/userId","externalUserId","userId","actorId"],ee=["waniwani/visitorId","visitorId"],te=["correlationId","openai/requestId"];function M(e){return e?v(e,X):void 0}function A(e){return e?v(e,G):void 0}function B(e){return e?v(e,J):void 0}function F(e){return e?v(e,Z):void 0}function O(e){return e?v(e,ee):void 0}function D(e){return e?v(e,te):void 0}var ne=[{key:"openai/sessionId",source:"chatgpt"},{key:"openai/session",source:"chatgpt"}],re=[{needle:"claude",source:"claude"},{needle:"chatgpt",source:"chatgpt"},{needle:"openai",source:"chatgpt"},{needle:"gemini",source:"gemini"}];function L(e,t){if(e){let r=e["waniwani/source"];if(typeof r=="string"&&r.length>0)return r;for(let{key:i,source:s}of ne){let a=e[i];if(typeof a=="string"&&a.length>0)return s}}let n=t?.name;if(typeof n=="string"&&n.length>0){let r=n.toLowerCase();for(let{needle:i,source:s}of re)if(r.includes(i))return s}}var ie="@waniwani/sdk";function y(e,t={}){let n=t.now??(()=>new Date),r=t.generateId??U,i=ae(e),s=I(e.meta),a=I(e.metadata),o=ce(e,s),c=p(e.eventId)??r(),g=ue(e.timestamp,n),d=p(e.source)??L(s)??t.source??ie,u=x(e)?{...e}:void 0,h={...a};return Object.keys(s).length>0&&(h.meta=s),u&&(h.rawLegacy=u),{id:c,type:"mcp.event",name:i,source:d,timestamp:g,correlation:o,properties:se(e,i),metadata:h,rawLegacy:u}}function U(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?`evt_${crypto.randomUUID()}`:`evt_${Math.random().toString(36).slice(2,10)}_${Date.now().toString(36)}`}function se(e,t){if(!x(e))return I(e.properties);let n=oe(e,t),r=I(e.properties);return{...n,...r}}function oe(e,t){switch(t){case"tool.called":{let n={};return p(e.toolName)&&(n.name=e.toolName),p(e.toolType)&&(n.type=e.toolType),n}case"quote.succeeded":{let n={};return typeof e.quoteAmount=="number"&&(n.amount=e.quoteAmount),p(e.quoteCurrency)&&(n.currency=e.quoteCurrency),n}case"link.clicked":{let n={};return p(e.linkUrl)&&(n.url=e.linkUrl),n}case"purchase.completed":{let n={};return typeof e.purchaseAmount=="number"&&(n.amount=e.purchaseAmount),p(e.purchaseCurrency)&&(n.currency=e.purchaseCurrency),n}default:return{}}}function ae(e){return x(e)?e.eventType:e.event}function ce(e,t){let n=p(e.requestId)??A(t),r=p(e.sessionId)??M(t),i=p(e.traceId)??B(t),s=p(e.externalUserId)??F(t),a=p(e.visitorId)??O(t),o=p(e.correlationId)??D(t)??n,c={};return r&&(c.sessionId=r),i&&(c.traceId=i),n&&(c.requestId=n),o&&(c.correlationId=o),s&&(c.externalUserId=s),a&&(c.visitorId=a),c}function ue(e,t){if(e instanceof Date)return e.toISOString();if(typeof e=="string"){let n=new Date(e);if(!Number.isNaN(n.getTime()))return n.toISOString()}return t().toISOString()}function I(e){return!e||typeof e!="object"||Array.isArray(e)?{}:e}function p(e){if(typeof e=="string"&&e.trim().length!==0)return e}function x(e){return"eventType"in e}function k(e){return{priceShown:({amount:t,currency:n,itemId:r,label:i,...s})=>e({event:"price_shown",properties:{amount:t,currency:n,itemId:r,label:i},...s}),pricesCompared:({options:t,...n})=>e({event:"prices_compared",properties:{options:t},...n}),optionSelected:({id:t,amount:n,currency:r,...i})=>e({event:"option_selected",properties:{id:t,amount:n,currency:r},...i}),leadQualified:t=>{let{externalId:n,email:r,name:i,...s}=t??{};return e({event:"lead_qualified",properties:{externalId:n,email:r,name:i},...s})},converted:({amount:t,currency:n,occurredAt:r,...i})=>e({event:"converted",properties:{amount:t,currency:n,occurredAt:r},...i})}}var de="/api/mcp/events/v2/batch";var W="@waniwani/sdk";var pe=new Set([401,403]),le=new Set([408,425,429,500,502,503,504]);function w(e){return new R(e)}var R=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(t){this.endpointUrl=ge(t.apiUrl,t.endpointPath??de),this.flushIntervalMs=t.flushIntervalMs??1e3,this.maxBatchSize=t.maxBatchSize??20,this.maxBufferSize=t.maxBufferSize??1e3,this.maxRetries=t.maxRetries??3,this.retryBaseDelayMs=t.retryBaseDelayMs??200,this.retryMaxDelayMs=t.retryMaxDelayMs??2e3,this.shutdownTimeoutMs=t.shutdownTimeoutMs??2e3,this.fetchFn=t.fetchFn??fetch,this.logger=t.logger??console,this.now=t.now??(()=>new Date),this.sleep=t.sleep??(n=>new Promise(r=>setTimeout(r,n))),this.apiKey=t.apiKey,this.sdkVersion=t.sdkVersion,this.flushIntervalMs>0&&(this.flushTimer=setInterval(()=>{this.flush()},this.flushIntervalMs)),this.registerBrowserTeardown()}enqueue(t){if(this.isStopped||this.isShuttingDown){this.logger.warn("[Waniwani] Tracking transport is stopped, dropping event %s",t.id);return}if(this.buffer.length>=this.maxBufferSize){let n=this.buffer.length-this.maxBufferSize+1;this.buffer.splice(0,n),this.logger.warn("[Waniwani] Tracking buffer overflow, dropped %d oldest event(s)",n)}if(this.buffer.push(t),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(t){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 n=t?.timeoutMs??this.shutdownTimeoutMs,r=this.flush();if(!Number.isFinite(n)||n<=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(n).then(()=>i)])===i?(this.isStopped=!0,{timedOut:!0,pendingEvents:this.pendingEvents()}):(this.isStopped=!0,{timedOut:!1,pendingEvents:this.pendingEvents()})}registerBrowserTeardown(){if(typeof document>"u"||typeof window>"u")return;let t=()=>{document.visibilityState==="hidden"&&this.keepaliveFlush()};document.addEventListener("visibilitychange",t),window.addEventListener("pagehide",()=>this.keepaliveFlush())}keepaliveFlush(){if(this.isStopped||this.buffer.length===0)return;let t=this.buffer.splice(0,this.buffer.length);this.sendKeepaliveChunk(t)}sendKeepaliveChunk(t){let n=JSON.stringify(this.makeBatchRequest(t));if(n.length>6e4&&t.length>1){let r=Math.ceil(t.length/2);this.sendKeepaliveChunk(t.slice(0,r)),this.sendKeepaliveChunk(t.slice(r));return}try{this.fetchFn(this.endpointUrl,{method:"POST",headers:this.requestHeaders(),body:n,keepalive:!0}).catch(()=>{})}catch{}}requestHeaders(){let t={"Content-Type":"application/json","X-WaniWani-SDK":W};return this.apiKey&&(t.Authorization=`Bearer ${this.apiKey}`),t}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 t=this.buffer.splice(0,this.maxBatchSize);await this.sendBatchWithRetry(t)}}async sendBatchWithRetry(t){let n=0,r=t;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(n>=this.maxRetries){this.logger.error("[Waniwani] Dropping %d event(s) after retry exhaustion: %s",r.length,i.reason);return}await this.sleep(this.backoffDelayMs(n)),n+=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(n>=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(n)),n+=1;continue}}}async sendBatchOnce(t){let n;try{n=await this.fetchFn(this.endpointUrl,{method:"POST",headers:this.requestHeaders(),body:JSON.stringify(this.makeBatchRequest(t))})}catch(s){return{kind:"retryable",reason:me(s)}}if(pe.has(n.status))return{kind:"auth",status:n.status};if(le.has(n.status))return{kind:"retryable",reason:`HTTP ${n.status}`};if(!n.ok)return{kind:"permanent",reason:`HTTP ${n.status}`};let r=await he(n);if(!r?.rejected||r.rejected.length===0)return{kind:"success"};let i=this.classifyRejectedEvents(t,r.rejected);return i.retryable.length===0&&i.permanent.length===0?{kind:"success"}:{kind:"partial",retryable:i.retryable,permanent:i.permanent}}makeBatchRequest(t){return{sentAt:this.now().toISOString(),source:{sdk:W,version:this.sdkVersion??"0.0.0"},events:t}}classifyRejectedEvents(t,n){let r=new Map(t.map(a=>[a.id,a])),i=[],s=[];for(let a of n){let o=r.get(a.eventId);if(o){if(fe(a)){i.push(o);continue}s.push(o)}}return{retryable:i,permanent:s}}backoffDelayMs(t){let n=this.retryBaseDelayMs*2**t;return Math.min(n,this.retryMaxDelayMs)}stopTransportForAuthFailure(t,n){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)",t,n+r)}};function fe(e){if(e.retryable===!0)return!0;let t=e.code.toLowerCase();return t.includes("timeout")||t.includes("temporary")||t.includes("unavailable")||t.includes("rate_limit")||t.includes("transient")||t.includes("server")}async function he(e){let t=await e.text();if(t)try{return JSON.parse(t)}catch{return}}function ge(e,t){let n=e.endsWith("/")?e:`${e}/`,r=t.startsWith("/")?t.slice(1):t;return`${n}${r}`}function me(e){return e instanceof Error?e.message:String(e)}function ve(e){let{apiUrl:t,endpointPath:n}=ye(e.endpoint),r=w({apiUrl:t,apiKey:e.token,endpointPath:n,flushIntervalMs:e.flushIntervalMs}),i,s=o=>typeof o=="function"?o():o,a=async o=>{let c=e.identity?.()??{},g=s(e.channelId),d=g===void 0?o.properties:{channelId:g,...o.properties},u=y({sessionId:c.sessionId,visitorId:c.visitorId,externalUserId:c.externalUserId??i,traceId:c.traceId,...o,properties:d,metadata:{...e.metadata,...o.metadata}},{source:s(e.source)});return r.enqueue(u),{eventId:u.id}};return{track:Object.assign(a,k(a)),identify(o,c){return i=o,a({event:"user.identified",externalUserId:o,properties:c})},flush:()=>r.flush(),shutdown:o=>r.shutdown(o)}}function ye(e){let t=new URL(e);return{apiUrl:t.origin,endpointPath:`${t.pathname}${t.search}`}}import{AsyncLocalStorage as Te}from"async_hooks";var V=globalThis,E=V.__waniwaniKbRetrievalStore;E||(E=new Te,V.__waniwaniKbRetrievalStore=E);var Ie=E;function K(e){try{Ie.getStore()?.searches.push(e)}catch{}}var ke="@waniwani/sdk";function j(e){let{apiUrl:t,apiKey:n}=e;function r(){if(!n)throw new Error("WANIWANI_API_KEY is not set");return n}async function i(s,a,o){let c=r(),g=`${t.replace(/\/$/,"")}${a}`,d={Authorization:`Bearer ${c}`,"X-WaniWani-SDK":ke},u={method:s,headers:d};o!==void 0&&(d["Content-Type"]="application/json",u.body=JSON.stringify(o));let h=await fetch(g,u);if(!h.ok){let N=await h.text().catch(()=>"");throw new T(N||`KB API error: HTTP ${h.status}`,h.status)}return(await h.json()).data}return{async ingest(s){return i("POST","/api/mcp/kb/ingest",{files:s})},async search(s,a){let o=await i("POST","/api/mcp/kb/search",{query:s,...a});return K({query:s,resultCount:o.length,results:o.map(c=>({source:c.source,heading:c.heading,score:c.score}))}),o},async sources(){return i("GET","/api/mcp/kb/sources")}}}function q(e){let{apiUrl:t,apiKey:n,tracking:r}=e;function i(){if(!n)throw new Error("WANIWANI_API_KEY is not set");return n}let s=n?w({apiUrl:t,apiKey:n,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 a(d){i();let u=y(d);return!u.correlation.sessionId&&!u.correlation.externalUserId&&!u.correlation.visitorId&&console.warn(`[waniwani] event "${u.name}" has no sessionId, externalUserId, or visitorId; the ingest API requires one and will reject it.`),s?.enqueue(u),{eventId:u.id}}let o=async d=>a(d),c=Object.assign(o,k(o)),g={async identify(d,u,h){i();let S=y({event:"user.identified",externalUserId:d,properties:u,meta:h});return s?.enqueue(S),{eventId:S.id}},track:c,async flush(){i(),await s?.flush()},async shutdown(d){return i(),await s?.shutdown({timeoutMs:d?.timeoutMs??r.shutdownTimeoutMs})??{timedOut:!1,pendingEvents:0}}};return s&&we(g,r.shutdownTimeoutMs),g}function we(e,t){if(typeof process>"u"||typeof process.once!="function"||typeof process.on!="function")return;let n=()=>{e.shutdown({timeoutMs:t})};process.once("beforeExit",n),process.once("SIGINT",n),process.once("SIGTERM",n)}function Ee(e){let n=e??P()??C(),r=n?.apiUrl??process.env.WANIWANI_API_URL??"https://app.waniwani.ai",i=n?.apiKey??process.env.WANIWANI_API_KEY,s={endpointPath:n?.tracking?.endpointPath??"/api/mcp/events/v2/batch",flushIntervalMs:n?.tracking?.flushIntervalMs??1e3,maxBatchSize:n?.tracking?.maxBatchSize??20,maxBufferSize:n?.tracking?.maxBufferSize??1e3,maxRetries:n?.tracking?.maxRetries??3,retryBaseDelayMs:n?.tracking?.retryBaseDelayMs??200,retryMaxDelayMs:n?.tracking?.retryMaxDelayMs??2e3,shutdownTimeoutMs:n?.tracking?.shutdownTimeoutMs??2e3},a={apiUrl:r,apiKey:i,tracking:s},o=q(a),c=j(a);return{...o,kb:c,_config:a}}export{_ as EVENT_TYPES,T as WaniWaniError,ve as createFrontendClient,Q as defineConfig,Ee as waniwani};
1
+ var y=class extends Error{constructor(n,r){super(n);this.status=r;this.name="WaniWaniError"}};import{existsSync as Y,readFileSync as z}from"fs";import{resolve as $}from"path";var H="waniwani.json",m;function b(){if(m!==void 0)return m;try{let e=$(process.cwd(),H);if(!Y(e))return m=null,null;let t=z(e,"utf-8");return m=JSON.parse(t),m}catch{return m=null,null}}var C="__waniwani_config__";function G(e){return globalThis[C]=e,e}function P(){return globalThis[C]}var _=["session.started","page.viewed","tool.called","link.clicked","widget_render","user.identified","price_shown","prices_compared","option_selected","lead_qualified","converted"];function v(e,t){for(let n of t){let r=e[n];if(typeof r=="string"&&r.length>0)return r}}var X=["waniwani/sessionId","openai/sessionId","openai/session","sessionId","conversationId","mcp-session-id"],Q=["waniwani/requestId","openai/requestId","requestId","mcp/requestId"],J=["waniwani/traceId","openai/traceId","traceId","mcp/traceId","openai/requestId","requestId"],Z=["waniwani/userId","openai/userId","externalUserId","userId","actorId"],ee=["waniwani/visitorId","visitorId"],te=["correlationId","openai/requestId"];function M(e){return e?v(e,X):void 0}function A(e){return e?v(e,Q):void 0}function B(e){return e?v(e,J):void 0}function F(e){return e?v(e,Z):void 0}function O(e){return e?v(e,ee):void 0}function D(e){return e?v(e,te):void 0}var ne=[{key:"openai/sessionId",source:"chatgpt"},{key:"openai/session",source:"chatgpt"}],re=[{needle:"claude",source:"claude"},{needle:"chatgpt",source:"chatgpt"},{needle:"openai",source:"chatgpt"},{needle:"gemini",source:"gemini"}];function U(e,t){if(e){let r=e["waniwani/source"];if(typeof r=="string"&&r.length>0)return r;for(let{key:i,source:s}of ne){let a=e[i];if(typeof a=="string"&&a.length>0)return s}}let n=t?.name;if(typeof n=="string"&&n.length>0){let r=n.toLowerCase();for(let{needle:i,source:s}of re)if(r.includes(i))return s}}var ie="@waniwani/sdk";function T(e,t={}){let n=t.now??(()=>new Date),r=t.generateId??L,i=ae(e),s=I(e.meta),a=I(e.metadata),o=ce(e,s),c=h(e.eventId)??r(),g=ue(e.timestamp,n),d=h(e.source)??U(s)??t.source??ie,u=x(e)?{...e}:void 0,f={...a};return Object.keys(s).length>0&&(f.meta=s),u&&(f.rawLegacy=u),{id:c,type:"mcp.event",name:i,source:d,timestamp:g,correlation:o,properties:se(e,i),metadata:f,rawLegacy:u}}function L(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?`evt_${crypto.randomUUID()}`:`evt_${Math.random().toString(36).slice(2,10)}_${Date.now().toString(36)}`}function se(e,t){if(!x(e))return I(e.properties);let n=oe(e,t),r=I(e.properties);return{...n,...r}}function oe(e,t){switch(t){case"tool.called":{let n={};return h(e.toolName)&&(n.name=e.toolName),h(e.toolType)&&(n.type=e.toolType),n}case"link.clicked":{let n={};return h(e.linkUrl)&&(n.url=e.linkUrl),n}default:return{}}}function ae(e){return x(e)?e.eventType:e.event}function ce(e,t){let n=h(e.requestId)??A(t),r=h(e.sessionId)??M(t),i=h(e.traceId)??B(t),s=h(e.externalUserId)??F(t),a=h(e.visitorId)??O(t),o=h(e.correlationId)??D(t)??n,c={};return r&&(c.sessionId=r),i&&(c.traceId=i),n&&(c.requestId=n),o&&(c.correlationId=o),s&&(c.externalUserId=s),a&&(c.visitorId=a),c}function ue(e,t){if(e instanceof Date)return e.toISOString();if(typeof e=="string"){let n=new Date(e);if(!Number.isNaN(n.getTime()))return n.toISOString()}return t().toISOString()}function I(e){return!e||typeof e!="object"||Array.isArray(e)?{}:e}function h(e){if(typeof e=="string"&&e.trim().length!==0)return e}function x(e){return"eventType"in e}function k(e){return{priceShown:({amount:t,currency:n,itemId:r,label:i,...s})=>e({event:"price_shown",properties:{amount:t,currency:n,itemId:r,label:i},...s}),pricesCompared:({options:t,...n})=>e({event:"prices_compared",properties:{options:t},...n}),optionSelected:({id:t,amount:n,currency:r,...i})=>e({event:"option_selected",properties:{id:t,amount:n,currency:r},...i}),leadQualified:t=>{let{externalId:n,email:r,name:i,...s}=t??{};return e({event:"lead_qualified",properties:{externalId:n,email:r,name:i},...s})},converted:({amount:t,currency:n,occurredAt:r,...i})=>e({event:"converted",properties:{amount:t,currency:n,occurredAt:r},...i})}}var de="/api/mcp/events/v2/batch";var W="@waniwani/sdk";var pe=new Set([401,403]),le=new Set([408,425,429,500,502,503,504]);function w(e){return new R(e)}var R=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(t){this.endpointUrl=ge(t.apiUrl,t.endpointPath??de),this.flushIntervalMs=t.flushIntervalMs??1e3,this.maxBatchSize=t.maxBatchSize??20,this.maxBufferSize=t.maxBufferSize??1e3,this.maxRetries=t.maxRetries??3,this.retryBaseDelayMs=t.retryBaseDelayMs??200,this.retryMaxDelayMs=t.retryMaxDelayMs??2e3,this.shutdownTimeoutMs=t.shutdownTimeoutMs??2e3,this.fetchFn=t.fetchFn??fetch,this.logger=t.logger??console,this.now=t.now??(()=>new Date),this.sleep=t.sleep??(n=>new Promise(r=>setTimeout(r,n))),this.apiKey=t.apiKey,this.sdkVersion=t.sdkVersion,this.flushIntervalMs>0&&(this.flushTimer=setInterval(()=>{this.flush()},this.flushIntervalMs)),this.registerBrowserTeardown()}enqueue(t){if(this.isStopped||this.isShuttingDown){this.logger.warn("[Waniwani] Tracking transport is stopped, dropping event %s",t.id);return}if(this.buffer.length>=this.maxBufferSize){let n=this.buffer.length-this.maxBufferSize+1;this.buffer.splice(0,n),this.logger.warn("[Waniwani] Tracking buffer overflow, dropped %d oldest event(s)",n)}if(this.buffer.push(t),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(t){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 n=t?.timeoutMs??this.shutdownTimeoutMs,r=this.flush();if(!Number.isFinite(n)||n<=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(n).then(()=>i)])===i?(this.isStopped=!0,{timedOut:!0,pendingEvents:this.pendingEvents()}):(this.isStopped=!0,{timedOut:!1,pendingEvents:this.pendingEvents()})}registerBrowserTeardown(){if(typeof document>"u"||typeof window>"u")return;let t=()=>{document.visibilityState==="hidden"&&this.keepaliveFlush()};document.addEventListener("visibilitychange",t),window.addEventListener("pagehide",()=>this.keepaliveFlush())}keepaliveFlush(){if(this.isStopped||this.buffer.length===0)return;let t=this.buffer.splice(0,this.buffer.length);this.sendKeepaliveChunk(t)}sendKeepaliveChunk(t){let n=JSON.stringify(this.makeBatchRequest(t));if(n.length>6e4&&t.length>1){let r=Math.ceil(t.length/2);this.sendKeepaliveChunk(t.slice(0,r)),this.sendKeepaliveChunk(t.slice(r));return}try{this.fetchFn(this.endpointUrl,{method:"POST",headers:this.requestHeaders(),body:n,keepalive:!0}).catch(()=>{})}catch{}}requestHeaders(){let t={"Content-Type":"application/json","X-WaniWani-SDK":W};return this.apiKey&&(t.Authorization=`Bearer ${this.apiKey}`),t}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 t=this.buffer.splice(0,this.maxBatchSize);await this.sendBatchWithRetry(t)}}async sendBatchWithRetry(t){let n=0,r=t;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(n>=this.maxRetries){this.logger.error("[Waniwani] Dropping %d event(s) after retry exhaustion: %s",r.length,i.reason);return}await this.sleep(this.backoffDelayMs(n)),n+=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(n>=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(n)),n+=1;continue}}}async sendBatchOnce(t){let n;try{n=await this.fetchFn(this.endpointUrl,{method:"POST",headers:this.requestHeaders(),body:JSON.stringify(this.makeBatchRequest(t))})}catch(s){return{kind:"retryable",reason:me(s)}}if(pe.has(n.status))return{kind:"auth",status:n.status};if(le.has(n.status))return{kind:"retryable",reason:`HTTP ${n.status}`};if(!n.ok)return{kind:"permanent",reason:`HTTP ${n.status}`};let r=await he(n);if(!r?.rejected||r.rejected.length===0)return{kind:"success"};let i=this.classifyRejectedEvents(t,r.rejected);return i.retryable.length===0&&i.permanent.length===0?{kind:"success"}:{kind:"partial",retryable:i.retryable,permanent:i.permanent}}makeBatchRequest(t){return{sentAt:this.now().toISOString(),source:{sdk:W,version:this.sdkVersion??"0.0.0"},events:t}}classifyRejectedEvents(t,n){let r=new Map(t.map(a=>[a.id,a])),i=[],s=[];for(let a of n){let o=r.get(a.eventId);if(o){if(fe(a)){i.push(o);continue}s.push(o)}}return{retryable:i,permanent:s}}backoffDelayMs(t){let n=this.retryBaseDelayMs*2**t;return Math.min(n,this.retryMaxDelayMs)}stopTransportForAuthFailure(t,n){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)",t,n+r)}};function fe(e){if(e.retryable===!0)return!0;let t=e.code.toLowerCase();return t.includes("timeout")||t.includes("temporary")||t.includes("unavailable")||t.includes("rate_limit")||t.includes("transient")||t.includes("server")}async function he(e){let t=await e.text();if(t)try{return JSON.parse(t)}catch{return}}function ge(e,t){let n=e.endsWith("/")?e:`${e}/`,r=t.startsWith("/")?t.slice(1):t;return`${n}${r}`}function me(e){return e instanceof Error?e.message:String(e)}function ve(e){let{apiUrl:t,endpointPath:n}=Te(e.endpoint),r=w({apiUrl:t,apiKey:e.token,endpointPath:n,flushIntervalMs:e.flushIntervalMs}),i,s=o=>typeof o=="function"?o():o,a=async o=>{let c=e.identity?.()??{},g=s(e.channelId),d=g===void 0?o.properties:{channelId:g,...o.properties},u=T({sessionId:c.sessionId,visitorId:c.visitorId,externalUserId:c.externalUserId??i,traceId:c.traceId,...o,properties:d,metadata:{...e.metadata,...o.metadata}},{source:s(e.source)});return r.enqueue(u),{eventId:u.id}};return{track:Object.assign(a,k(a)),identify(o,c){return i=o,a({event:"user.identified",externalUserId:o,properties:c})},flush:()=>r.flush(),shutdown:o=>r.shutdown(o)}}function Te(e){let t=new URL(e);return{apiUrl:t.origin,endpointPath:`${t.pathname}${t.search}`}}import{AsyncLocalStorage as ye}from"async_hooks";var K=globalThis,E=K.__waniwaniKbRetrievalStore;E||(E=new ye,K.__waniwaniKbRetrievalStore=E);var Ie=E;function V(e){try{Ie.getStore()?.searches.push(e)}catch{}}var ke="@waniwani/sdk";function j(e){let{apiUrl:t,apiKey:n}=e;function r(){if(!n)throw new Error("WANIWANI_API_KEY is not set");return n}async function i(s,a,o){let c=r(),g=`${t.replace(/\/$/,"")}${a}`,d={Authorization:`Bearer ${c}`,"X-WaniWani-SDK":ke},u={method:s,headers:d};o!==void 0&&(d["Content-Type"]="application/json",u.body=JSON.stringify(o));let f=await fetch(g,u);if(!f.ok){let q=await f.text().catch(()=>"");throw new y(q||`KB API error: HTTP ${f.status}`,f.status)}return(await f.json()).data}return{async ingest(s){return i("POST","/api/mcp/kb/ingest",{files:s})},async search(s,a){let o=await i("POST","/api/mcp/kb/search",{query:s,...a});return V({query:s,resultCount:o.length,results:o.map(c=>({source:c.source,heading:c.heading,score:c.score}))}),o},async sources(){return i("GET","/api/mcp/kb/sources")}}}function N(e){let{apiUrl:t,apiKey:n,tracking:r}=e;function i(){if(!n)throw new Error("WANIWANI_API_KEY is not set");return n}let s=n?w({apiUrl:t,apiKey:n,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 a(d){i();let u=T(d);return!u.correlation.sessionId&&!u.correlation.externalUserId&&!u.correlation.visitorId&&console.warn(`[waniwani] event "${u.name}" has no sessionId, externalUserId, or visitorId; the ingest API requires one and will reject it.`),s?.enqueue(u),{eventId:u.id}}let o=async d=>a(d),c=Object.assign(o,k(o)),g={async identify(d,u,f){i();let S=T({event:"user.identified",externalUserId:d,properties:u,meta:f});return s?.enqueue(S),{eventId:S.id}},track:c,async flush(){i(),await s?.flush()},async shutdown(d){return i(),await s?.shutdown({timeoutMs:d?.timeoutMs??r.shutdownTimeoutMs})??{timedOut:!1,pendingEvents:0}}};return s&&we(g,r.shutdownTimeoutMs),g}function we(e,t){if(typeof process>"u"||typeof process.once!="function"||typeof process.on!="function")return;let n=()=>{e.shutdown({timeoutMs:t})};process.once("beforeExit",n),process.once("SIGINT",n),process.once("SIGTERM",n)}function Ee(e){let n=e??b()??P(),r=n?.apiUrl??process.env.WANIWANI_API_URL??"https://app.waniwani.ai",i=n?.apiKey??process.env.WANIWANI_API_KEY,s={endpointPath:n?.tracking?.endpointPath??"/api/mcp/events/v2/batch",flushIntervalMs:n?.tracking?.flushIntervalMs??1e3,maxBatchSize:n?.tracking?.maxBatchSize??20,maxBufferSize:n?.tracking?.maxBufferSize??1e3,maxRetries:n?.tracking?.maxRetries??3,retryBaseDelayMs:n?.tracking?.retryBaseDelayMs??200,retryMaxDelayMs:n?.tracking?.retryMaxDelayMs??2e3,shutdownTimeoutMs:n?.tracking?.shutdownTimeoutMs??2e3},a={apiUrl:r,apiKey:i,tracking:s},o=N(a),c=j(a);return{...o,kb:c,_config:a}}export{_ as EVENT_TYPES,y as WaniWaniError,ve as createFrontendClient,G as defineConfig,Ee as waniwani};
2
2
  //# sourceMappingURL=index.js.map