@waniwani/sdk 0.0.12 → 0.0.13
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/chat/index.d.ts +20 -2
- package/dist/chat/index.js +1 -1
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/next-js/index.d.ts +178 -0
- package/dist/chat/next-js/index.js +2 -0
- package/dist/chat/next-js/index.js.map +1 -0
- package/dist/chat/server/index.d.ts +10 -2
- package/dist/chat/styles.css +1 -1
- package/dist/{chunk-SCDEAZN4.js → chunk-DGSC74SV.js} +1 -1
- package/dist/chunk-DGSC74SV.js.map +1 -0
- package/dist/{chunk-OVQDB7QX.js → chunk-ZUGQBRJF.js} +1 -1
- package/dist/chunk-ZUGQBRJF.js.map +1 -0
- package/dist/index.d.ts +15 -64
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts +267 -105
- package/dist/mcp/index.js +3 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/react.js +2 -2
- package/dist/mcp/react.js.map +1 -1
- package/dist/{mcp-apps-client-DZ3L5O3U.js → mcp-apps-client-GILGJJZP.js} +1 -1
- package/dist/mcp-apps-client-GILGJJZP.js.map +1 -0
- package/dist/{openai-client-UL6T463M.js → openai-client-3M6MDERR.js} +2 -2
- package/dist/openai-client-3M6MDERR.js.map +1 -0
- package/dist/platform-GKYYQBCS.js +3 -0
- package/package.json +7 -3
- package/dist/chunk-OVQDB7QX.js.map +0 -1
- package/dist/chunk-SCDEAZN4.js.map +0 -1
- package/dist/mcp-apps-client-DZ3L5O3U.js.map +0 -1
- package/dist/openai-client-UL6T463M.js.map +0 -1
- package/dist/platform-4QZXTYT5.js +0 -3
- /package/dist/{platform-4QZXTYT5.js.map → platform-GKYYQBCS.js.map} +0 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { UIMessage } from 'ai';
|
|
2
|
+
|
|
3
|
+
type EventType = "tool.called" | "quote.requested" | "quote.succeeded" | "quote.failed" | "link.clicked" | "purchase.completed";
|
|
4
|
+
interface ToolCalledProperties {
|
|
5
|
+
name?: string;
|
|
6
|
+
type?: "pricing" | "product_info" | "availability" | "support" | "other";
|
|
7
|
+
}
|
|
8
|
+
interface QuoteSucceededProperties {
|
|
9
|
+
amount?: number;
|
|
10
|
+
currency?: string;
|
|
11
|
+
}
|
|
12
|
+
interface LinkClickedProperties {
|
|
13
|
+
url?: string;
|
|
14
|
+
}
|
|
15
|
+
interface PurchaseCompletedProperties {
|
|
16
|
+
amount?: number;
|
|
17
|
+
currency?: string;
|
|
18
|
+
}
|
|
19
|
+
interface BaseEvent {
|
|
20
|
+
/**
|
|
21
|
+
* Event type.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* wani.track({
|
|
26
|
+
* event: 'tool.called',
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
event: EventType;
|
|
31
|
+
/**
|
|
32
|
+
* Event properties.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* wani.track({
|
|
37
|
+
* event: 'tool.called',
|
|
38
|
+
* properties: { name: 'search' },
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
properties?: Record<string, unknown>;
|
|
43
|
+
/**
|
|
44
|
+
* MCP request metadata passed through to the API.
|
|
45
|
+
*
|
|
46
|
+
* Location varies by MCP library:
|
|
47
|
+
* - `@vercel/mcp-handler`: `extra._meta`
|
|
48
|
+
* - `@modelcontextprotocol/sdk`: `request.params._meta`
|
|
49
|
+
*/
|
|
50
|
+
meta?: Record<string, unknown>;
|
|
51
|
+
}
|
|
52
|
+
type TrackEvent = ({
|
|
53
|
+
event: "tool.called";
|
|
54
|
+
properties: ToolCalledProperties;
|
|
55
|
+
} & BaseEvent) | ({
|
|
56
|
+
event: "quote.requested";
|
|
57
|
+
} & BaseEvent) | ({
|
|
58
|
+
event: "quote.succeeded";
|
|
59
|
+
properties: QuoteSucceededProperties;
|
|
60
|
+
} & BaseEvent) | ({
|
|
61
|
+
event: "quote.failed";
|
|
62
|
+
} & BaseEvent) | ({
|
|
63
|
+
event: "link.clicked";
|
|
64
|
+
properties: LinkClickedProperties;
|
|
65
|
+
} & BaseEvent) | ({
|
|
66
|
+
event: "purchase.completed";
|
|
67
|
+
properties: PurchaseCompletedProperties;
|
|
68
|
+
} & BaseEvent);
|
|
69
|
+
/**
|
|
70
|
+
* Tracking module methods for WaniWaniClient
|
|
71
|
+
*/
|
|
72
|
+
interface TrackingClient {
|
|
73
|
+
/**
|
|
74
|
+
* Track an event. Pass MCP request metadata to auto-extract session, user,
|
|
75
|
+
* and location info from the provider (OpenAI, Anthropic, etc.).
|
|
76
|
+
*/
|
|
77
|
+
track: (event: TrackEvent) => Promise<{
|
|
78
|
+
eventId: string;
|
|
79
|
+
}>;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* WaniWani SDK Client
|
|
84
|
+
*
|
|
85
|
+
* Extends with each module:
|
|
86
|
+
* - TrackingClient: track(), getOrCreateSession()
|
|
87
|
+
*
|
|
88
|
+
* Pass this client to framework adapters:
|
|
89
|
+
* - `toNextJsHandler(wani, { ... })` for Next.js route handlers
|
|
90
|
+
*/
|
|
91
|
+
interface WaniWaniClient extends TrackingClient {
|
|
92
|
+
/** @internal Resolved config — used by framework adapters */
|
|
93
|
+
readonly _config: InternalConfig;
|
|
94
|
+
}
|
|
95
|
+
interface InternalConfig {
|
|
96
|
+
baseUrl: string;
|
|
97
|
+
apiKey: string | undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
interface BeforeRequestContext {
|
|
101
|
+
/** The conversation messages from the client */
|
|
102
|
+
messages: UIMessage[];
|
|
103
|
+
/** Session identifier for conversation continuity */
|
|
104
|
+
sessionId?: string;
|
|
105
|
+
/** The original HTTP Request object */
|
|
106
|
+
request: Request;
|
|
107
|
+
}
|
|
108
|
+
type BeforeRequestResult = {
|
|
109
|
+
/** Override messages (e.g., filtered, augmented) */
|
|
110
|
+
messages?: UIMessage[];
|
|
111
|
+
/** Override the system prompt for this request */
|
|
112
|
+
systemPrompt?: string;
|
|
113
|
+
/** Override sessionId */
|
|
114
|
+
sessionId?: string;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
interface ChatOptions {
|
|
118
|
+
/**
|
|
119
|
+
* System prompt for the assistant.
|
|
120
|
+
* Can be overridden per-request via `beforeRequest`.
|
|
121
|
+
*/
|
|
122
|
+
systemPrompt?: string;
|
|
123
|
+
/**
|
|
124
|
+
* Maximum number of tool call steps. Defaults to 5.
|
|
125
|
+
*/
|
|
126
|
+
maxSteps?: number;
|
|
127
|
+
/**
|
|
128
|
+
* Hook called before each request is forwarded to the WaniWani API.
|
|
129
|
+
* - Return void to use defaults.
|
|
130
|
+
* - Return an object to override messages, systemPrompt, or sessionId.
|
|
131
|
+
* - Throw to reject the request (the error message is returned as JSON).
|
|
132
|
+
*/
|
|
133
|
+
beforeRequest?: (context: BeforeRequestContext) => Promise<BeforeRequestResult | undefined> | BeforeRequestResult | undefined;
|
|
134
|
+
/**
|
|
135
|
+
* Override the MCP server URL directly, bypassing config resolution.
|
|
136
|
+
* Useful for development/testing when pointing to a local MCP server.
|
|
137
|
+
*/
|
|
138
|
+
mcpServerUrl?: string;
|
|
139
|
+
}
|
|
140
|
+
interface NextJsHandlerOptions {
|
|
141
|
+
/** Chat handler configuration */
|
|
142
|
+
chat?: ChatOptions;
|
|
143
|
+
}
|
|
144
|
+
interface NextJsHandlerResult {
|
|
145
|
+
/** GET handler: routes sub-paths (e.g. /resource for MCP widget content) */
|
|
146
|
+
GET: (request: Request) => Promise<Response>;
|
|
147
|
+
/** POST handler: proxies chat messages to the WaniWani API */
|
|
148
|
+
POST: (request: Request) => Promise<Response>;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Create Next.js route handlers from a WaniWani client.
|
|
153
|
+
*
|
|
154
|
+
* Returns `{ GET, POST }` for use with catch-all routes.
|
|
155
|
+
* Mount at `app/api/waniwani/[[...path]]/route.ts`:
|
|
156
|
+
*
|
|
157
|
+
* - `POST /api/waniwani` → chat (proxied to WaniWani API)
|
|
158
|
+
* - `GET /api/waniwani/resource?uri=…` → MCP resource content
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```typescript
|
|
162
|
+
* // app/api/waniwani/[[...path]]/route.ts
|
|
163
|
+
* import { waniwani } from "@waniwani/sdk";
|
|
164
|
+
* import { toNextJsHandler } from "@waniwani/sdk/next-js";
|
|
165
|
+
*
|
|
166
|
+
* const wani = waniwani();
|
|
167
|
+
*
|
|
168
|
+
* export const { GET, POST } = toNextJsHandler(wani, {
|
|
169
|
+
* chat: {
|
|
170
|
+
* systemPrompt: "You are a helpful assistant.",
|
|
171
|
+
* mcpServerUrl: process.env.MCP_SERVER_URL!,
|
|
172
|
+
* },
|
|
173
|
+
* });
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
declare function toNextJsHandler(client: WaniWaniClient, options?: NextJsHandlerOptions): NextJsHandlerResult;
|
|
177
|
+
|
|
178
|
+
export { type NextJsHandlerOptions, type NextJsHandlerResult, toNextJsHandler };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var u=class extends Error{constructor(t,o){super(t);this.status=o;this.name="WaniWaniError"}};function v(p){let{apiKey:s,baseUrl:t,systemPrompt:o,maxSteps:m,beforeRequest:e,mcpServerUrl:i,resolveConfig:c}=p;return async function(f){try{let l=await f.json(),r=l.messages??[],a=l.sessionId,R=o;if(e)try{let n=await e({messages:r,sessionId:a,request:f});n&&(n.messages&&(r=n.messages),n.systemPrompt!==void 0&&(R=n.systemPrompt),n.sessionId!==void 0&&(a=n.sessionId))}catch(n){let H=n instanceof u?n.status:400,P=n instanceof Error?n.message:"Request rejected";return Response.json({error:P},{status:H})}let C=i??(await c()).mcpServerUrl,d=await fetch(`${t}/api/mcp/chat`,{method:"POST",headers:{"Content-Type":"application/json",...s?{Authorization:`Bearer ${s}`}:{}},body:JSON.stringify({messages:r,mcpServerUrl:C,sessionId:a,systemPrompt:R,maxSteps:m}),signal:f.signal});if(!d.ok){let n=await d.text().catch(()=>"");return new Response(n,{status:d.status,headers:{"Content-Type":d.headers.get("Content-Type")??"application/json"}})}return new Response(d.body,{status:d.status,headers:{"Content-Type":d.headers.get("Content-Type")??"text/event-stream"}})}catch(l){let r=l instanceof Error?l.message:"Unknown error occurred",a=l instanceof u?l.status:500;return Response.json({error:r},{status:a})}}}function w(p){let{mcpServerUrl:s,resolveConfig:t}=p;return async function(m){try{let e=m.searchParams.get("uri");if(!e)return Response.json({error:"Missing uri query parameter"},{status:400});let i=s??(await t()).mcpServerUrl,c,y;try{[{createMCPClient:c},{StreamableHTTPClientTransport:y}]=await Promise.all([import("@ai-sdk/mcp"),import("@modelcontextprotocol/sdk/client/streamableHttp.js")])}catch{return Response.json({error:"MCP resource handler requires @ai-sdk/mcp and @modelcontextprotocol/sdk. Install them to enable resource serving."},{status:501})}let f=await c({transport:new y(new URL(i))});try{let r=(await f.readResource({uri:e})).contents[0];if(!r)return Response.json({error:"Resource not found"},{status:404});let a;return"text"in r&&typeof r.text=="string"?a=r.text:"blob"in r&&typeof r.blob=="string"&&(a=atob(r.blob)),a?new Response(a,{headers:{"Content-Type":"text/html","Cache-Control":"private, max-age=300"}}):Response.json({error:"Resource has no content"},{status:404})}finally{await f.close()}}catch(e){let i=e instanceof Error?e.message:"Unknown error occurred",c=e instanceof u?e.status:500;return Response.json({error:i},{status:c})}}}var A=300*1e3;function x(p,s){let t=null,o=null;return async function(){if(t&&Date.now()<t.expiresAt)return t.config;if(o)return o;o=(async()=>{if(!s)throw new u("WANIWANI_API_KEY is required for createChatHandler",401);let e=await fetch(`${p}/api/mcp/environments/config`,{method:"GET",headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json"}});if(!e.ok){let c=await e.text().catch(()=>"");throw new u(`Failed to resolve MCP environment config: ${e.status} ${c}`,e.status)}let i=await e.json();return t={config:i,expiresAt:Date.now()+A},i})();try{return await o}finally{o=null}}}function b(p={}){let{apiKey:s=process.env.WANIWANI_API_KEY,baseUrl:t="https://app.waniwani.ai",systemPrompt:o,maxSteps:m=5,beforeRequest:e,mcpServerUrl:i}=p,c=x(t,s),y=v({apiKey:s,baseUrl:t,systemPrompt:o,maxSteps:m,beforeRequest:e,mcpServerUrl:i,resolveConfig:c}),f=w({mcpServerUrl:i,resolveConfig:c});function l(r){let a=new URL(r.url);return a.pathname.replace(/\/$/,"").split("/").filter(Boolean).at(-1)==="resource"?f(a):Promise.resolve(Response.json({error:"Not found"},{status:404}))}return{handleChat:y,handleResource:f,routeGet:l}}function G(p,s){let{apiKey:t,baseUrl:o}=p._config,m=b({...s?.chat,apiKey:t,baseUrl:o});return{POST:m.handleChat,GET:m.routeGet}}export{G as toNextJsHandler};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/error.ts","../../../src/chat/server/handle-chat.ts","../../../src/chat/server/handle-resource.ts","../../../src/chat/server/mcp-config-resolver.ts","../../../src/chat/server/api-handler.ts","../../../src/chat/server/next-js/index.ts"],"sourcesContent":["// WaniWani SDK - Errors\n\nexport class WaniWaniError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic status: number,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"WaniWaniError\";\n\t}\n}\n","// Handle Chat - Proxies chat requests to the WaniWani API\n\nimport { WaniWaniError } from \"../../error\";\nimport type { ApiHandlerDeps } from \"./@types\";\n\nexport function createChatRequestHandler(deps: ApiHandlerDeps) {\n\tconst {\n\t\tapiKey,\n\t\tbaseUrl,\n\t\tsystemPrompt,\n\t\tmaxSteps,\n\t\tbeforeRequest,\n\t\tmcpServerUrl: mcpServerUrlOverride,\n\t\tresolveConfig,\n\t} = deps;\n\n\treturn async function handleChat(request: Request): Promise<Response> {\n\t\ttry {\n\t\t\t// 1. Parse request body\n\t\t\tconst body = await request.json();\n\t\t\tlet messages = body.messages ?? [];\n\t\t\tlet sessionId: string | undefined = body.sessionId;\n\t\t\tlet effectiveSystemPrompt = systemPrompt;\n\n\t\t\t// 2. Run beforeRequest hook\n\t\t\tif (beforeRequest) {\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await beforeRequest({\n\t\t\t\t\t\tmessages,\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\trequest,\n\t\t\t\t\t});\n\n\t\t\t\t\tif (result) {\n\t\t\t\t\t\tif (result.messages) messages = result.messages;\n\t\t\t\t\t\tif (result.systemPrompt !== undefined)\n\t\t\t\t\t\t\teffectiveSystemPrompt = result.systemPrompt;\n\t\t\t\t\t\tif (result.sessionId !== undefined) sessionId = result.sessionId;\n\t\t\t\t\t}\n\t\t\t\t} catch (hookError) {\n\t\t\t\t\tconst status =\n\t\t\t\t\t\thookError instanceof WaniWaniError ? hookError.status : 400;\n\t\t\t\t\tconst message =\n\t\t\t\t\t\thookError instanceof Error ? hookError.message : \"Request rejected\";\n\t\t\t\t\treturn Response.json({ error: message }, { status });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 3. Resolve MCP server URL\n\t\t\tconst mcpServerUrl =\n\t\t\t\tmcpServerUrlOverride ?? (await resolveConfig()).mcpServerUrl;\n\n\t\t\t// 4. Forward to WaniWani API\n\t\t\tconst response = await fetch(`${baseUrl}/api/mcp/chat`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmessages,\n\t\t\t\t\tmcpServerUrl,\n\t\t\t\t\tsessionId,\n\t\t\t\t\tsystemPrompt: effectiveSystemPrompt,\n\t\t\t\t\tmaxSteps,\n\t\t\t\t}),\n\t\t\t\tsignal: request.signal,\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errorBody = await response.text().catch(() => \"\");\n\t\t\t\treturn new Response(errorBody, {\n\t\t\t\t\tstatus: response.status,\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"Content-Type\":\n\t\t\t\t\t\t\tresponse.headers.get(\"Content-Type\") ?? \"application/json\",\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// 5. Stream the response back\n\t\t\treturn new Response(response.body, {\n\t\t\t\tstatus: response.status,\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\":\n\t\t\t\t\t\tresponse.headers.get(\"Content-Type\") ?? \"text/event-stream\",\n\t\t\t\t},\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconst message =\n\t\t\t\terror instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tconst status = error instanceof WaniWaniError ? error.status : 500;\n\n\t\t\treturn Response.json({ error: message }, { status });\n\t\t}\n\t};\n}\n","// Handle Resource - Serves MCP resource content (HTML widgets)\n\nimport { WaniWaniError } from \"../../error\";\nimport type { ResourceHandlerDeps } from \"./@types\";\n\nexport function createResourceHandler(deps: ResourceHandlerDeps) {\n\tconst { mcpServerUrl: mcpServerUrlOverride, resolveConfig } = deps;\n\n\treturn async function handleResource(url: URL): Promise<Response> {\n\t\ttry {\n\t\t\tconst uri = url.searchParams.get(\"uri\");\n\n\t\t\tif (!uri) {\n\t\t\t\treturn Response.json(\n\t\t\t\t\t{ error: \"Missing uri query parameter\" },\n\t\t\t\t\t{ status: 400 },\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst mcpServerUrl =\n\t\t\t\tmcpServerUrlOverride ?? (await resolveConfig()).mcpServerUrl;\n\n\t\t\t// Dynamic imports — these are optional peer dependencies\n\t\t\tlet createMCPClient: typeof import(\"@ai-sdk/mcp\")[\"createMCPClient\"];\n\t\t\tlet StreamableHTTPClientTransport: typeof import(\"@modelcontextprotocol/sdk/client/streamableHttp.js\")[\"StreamableHTTPClientTransport\"];\n\n\t\t\ttry {\n\t\t\t\t[{ createMCPClient }, { StreamableHTTPClientTransport }] =\n\t\t\t\t\tawait Promise.all([\n\t\t\t\t\t\timport(\"@ai-sdk/mcp\"),\n\t\t\t\t\t\timport(\"@modelcontextprotocol/sdk/client/streamableHttp.js\"),\n\t\t\t\t\t]);\n\t\t\t} catch {\n\t\t\t\treturn Response.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror:\n\t\t\t\t\t\t\t\"MCP resource handler requires @ai-sdk/mcp and @modelcontextprotocol/sdk. Install them to enable resource serving.\",\n\t\t\t\t\t},\n\t\t\t\t\t{ status: 501 },\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst mcp = await createMCPClient({\n\t\t\t\ttransport: new StreamableHTTPClientTransport(new URL(mcpServerUrl)),\n\t\t\t});\n\n\t\t\ttry {\n\t\t\t\tconst result = await mcp.readResource({ uri });\n\n\t\t\t\tconst content = result.contents[0];\n\t\t\t\tif (!content) {\n\t\t\t\t\treturn Response.json(\n\t\t\t\t\t\t{ error: \"Resource not found\" },\n\t\t\t\t\t\t{ status: 404 },\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tlet html: string | undefined;\n\t\t\t\tif (\"text\" in content && typeof content.text === \"string\") {\n\t\t\t\t\thtml = content.text;\n\t\t\t\t} else if (\"blob\" in content && typeof content.blob === \"string\") {\n\t\t\t\t\thtml = atob(content.blob);\n\t\t\t\t}\n\n\t\t\t\tif (!html) {\n\t\t\t\t\treturn Response.json(\n\t\t\t\t\t\t{ error: \"Resource has no content\" },\n\t\t\t\t\t\t{ status: 404 },\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn new Response(html, {\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"Content-Type\": \"text/html\",\n\t\t\t\t\t\t\"Cache-Control\": \"private, max-age=300\",\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\tawait mcp.close();\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst message =\n\t\t\t\terror instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tconst status = error instanceof WaniWaniError ? error.status : 500;\n\t\t\treturn Response.json({ error: message }, { status });\n\t\t}\n\t};\n}\n","// MCP Config Resolver - Lazy-loads and caches MCP environment config\n\nimport { WaniWaniError } from \"../../error\";\n\ninterface McpEnvironmentConfig {\n\tmcpServerUrl: string;\n}\n\nconst TTL_MS = 5 * 60 * 1000; // 5 minutes\n\nexport function createMcpConfigResolver(\n\tbaseUrl: string,\n\tapiKey: string | undefined,\n) {\n\tlet cached: { config: McpEnvironmentConfig; expiresAt: number } | null = null;\n\tlet inflight: Promise<McpEnvironmentConfig> | null = null;\n\n\treturn async function resolve(): Promise<McpEnvironmentConfig> {\n\t\tif (cached && Date.now() < cached.expiresAt) {\n\t\t\treturn cached.config;\n\t\t}\n\n\t\t// Deduplicate concurrent requests (cold start scenario)\n\t\tif (inflight) {\n\t\t\treturn inflight;\n\t\t}\n\n\t\tinflight = (async () => {\n\t\t\tif (!apiKey) {\n\t\t\t\tthrow new WaniWaniError(\n\t\t\t\t\t\"WANIWANI_API_KEY is required for createChatHandler\",\n\t\t\t\t\t401,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst response = await fetch(`${baseUrl}/api/mcp/environments/config`, {\n\t\t\t\tmethod: \"GET\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${apiKey}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst body = await response.text().catch(() => \"\");\n\t\t\t\tthrow new WaniWaniError(\n\t\t\t\t\t`Failed to resolve MCP environment config: ${response.status} ${body}`,\n\t\t\t\t\tresponse.status,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst data = (await response.json()) as McpEnvironmentConfig;\n\t\t\tcached = { config: data, expiresAt: Date.now() + TTL_MS };\n\t\t\treturn data;\n\t\t})();\n\n\t\ttry {\n\t\t\treturn await inflight;\n\t\t} finally {\n\t\t\tinflight = null;\n\t\t}\n\t};\n}\n","// API Handler - Composes chat and resource handlers into a unified API handler\n\nimport type { ApiHandler, ApiHandlerOptions } from \"./@types\";\nimport { createChatRequestHandler } from \"./handle-chat\";\nimport { createResourceHandler } from \"./handle-resource\";\nimport { createMcpConfigResolver } from \"./mcp-config-resolver\";\n\n/**\n * Create a framework-agnostic API handler for chat and MCP resources.\n *\n * Returns an object with handler methods that can be wired into\n * any framework (Next.js, Hono, Express, etc.):\n *\n * - `handleChat(request)` → proxies chat messages to WaniWani API\n * - `handleResource(url)` → serves MCP resource content (HTML widgets)\n * - `routeGet(request)` → routes GET sub-paths (e.g. /resource)\n *\n * @example\n * ```typescript\n * import { waniwani } from \"@waniwani/sdk\";\n * import { toNextJsHandler } from \"@waniwani/sdk/next-js\";\n *\n * const wani = waniwani();\n *\n * export const { GET, POST } = toNextJsHandler(wani, {\n * chat: { systemPrompt: \"You are a helpful assistant.\" },\n * });\n * ```\n */\nexport function createApiHandler(options: ApiHandlerOptions = {}): ApiHandler {\n\tconst {\n\t\tapiKey = process.env.WANIWANI_API_KEY,\n\t\tbaseUrl = \"https://app.waniwani.ai\",\n\t\tsystemPrompt,\n\t\tmaxSteps = 5,\n\t\tbeforeRequest,\n\t\tmcpServerUrl,\n\t} = options;\n\n\tconst resolveConfig = createMcpConfigResolver(baseUrl, apiKey);\n\n\tconst handleChat = createChatRequestHandler({\n\t\tapiKey,\n\t\tbaseUrl,\n\t\tsystemPrompt,\n\t\tmaxSteps,\n\t\tbeforeRequest,\n\t\tmcpServerUrl,\n\t\tresolveConfig,\n\t});\n\n\tconst handleResource = createResourceHandler({\n\t\tmcpServerUrl,\n\t\tresolveConfig,\n\t});\n\n\tfunction routeGet(request: Request): Promise<Response> {\n\t\tconst url = new URL(request.url);\n\t\tconst segments = url.pathname.replace(/\\/$/, \"\").split(\"/\").filter(Boolean);\n\t\tconst subRoute = segments.at(-1);\n\n\t\tif (subRoute === \"resource\") {\n\t\t\treturn handleResource(url);\n\t\t}\n\n\t\treturn Promise.resolve(\n\t\t\tResponse.json({ error: \"Not found\" }, { status: 404 }),\n\t\t);\n\t}\n\n\treturn { handleChat, handleResource, routeGet };\n}\n","// WaniWani SDK - Next.js Adapter\n\nimport type { WaniWaniClient } from \"../../../types.js\";\nimport { createApiHandler } from \"../api-handler.js\";\nimport type { NextJsHandlerOptions, NextJsHandlerResult } from \"./@types.js\";\n\nexport type { NextJsHandlerOptions, NextJsHandlerResult } from \"./@types.js\";\n\n/**\n * Create Next.js route handlers from a WaniWani client.\n *\n * Returns `{ GET, POST }` for use with catch-all routes.\n * Mount at `app/api/waniwani/[[...path]]/route.ts`:\n *\n * - `POST /api/waniwani` → chat (proxied to WaniWani API)\n * - `GET /api/waniwani/resource?uri=…` → MCP resource content\n *\n * @example\n * ```typescript\n * // app/api/waniwani/[[...path]]/route.ts\n * import { waniwani } from \"@waniwani/sdk\";\n * import { toNextJsHandler } from \"@waniwani/sdk/next-js\";\n *\n * const wani = waniwani();\n *\n * export const { GET, POST } = toNextJsHandler(wani, {\n * chat: {\n * systemPrompt: \"You are a helpful assistant.\",\n * mcpServerUrl: process.env.MCP_SERVER_URL!,\n * },\n * });\n * ```\n */\nexport function toNextJsHandler(\n\tclient: WaniWaniClient,\n\toptions?: NextJsHandlerOptions,\n): NextJsHandlerResult {\n\tconst { apiKey, baseUrl } = client._config;\n\n\tconst handler = createApiHandler({\n\t\t...options?.chat,\n\t\tapiKey,\n\t\tbaseUrl,\n\t});\n\n\treturn {\n\t\tPOST: handler.handleChat,\n\t\tGET: handler.routeGet,\n\t};\n}\n"],"mappings":"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","names":["WaniWaniError","message","status","createChatRequestHandler","deps","apiKey","baseUrl","systemPrompt","maxSteps","beforeRequest","mcpServerUrlOverride","resolveConfig","request","body","messages","sessionId","effectiveSystemPrompt","result","hookError","status","WaniWaniError","message","mcpServerUrl","response","errorBody","error","createResourceHandler","deps","mcpServerUrlOverride","resolveConfig","url","uri","mcpServerUrl","createMCPClient","StreamableHTTPClientTransport","mcp","content","html","error","message","status","WaniWaniError","TTL_MS","createMcpConfigResolver","baseUrl","apiKey","cached","inflight","WaniWaniError","response","body","data","createApiHandler","options","apiKey","baseUrl","systemPrompt","maxSteps","beforeRequest","mcpServerUrl","resolveConfig","createMcpConfigResolver","handleChat","createChatRequestHandler","handleResource","createResourceHandler","routeGet","request","url","toNextJsHandler","client","options","apiKey","baseUrl","handler","createApiHandler"]}
|
|
@@ -21,7 +21,7 @@ type BeforeRequestResult = {
|
|
|
21
21
|
/** Override sessionId */
|
|
22
22
|
sessionId?: string;
|
|
23
23
|
};
|
|
24
|
-
interface
|
|
24
|
+
interface ApiHandlerOptions {
|
|
25
25
|
/**
|
|
26
26
|
* Your WaniWani API key.
|
|
27
27
|
* Defaults to process.env.WANIWANI_API_KEY.
|
|
@@ -54,5 +54,13 @@ interface ChatHandlerOptions {
|
|
|
54
54
|
*/
|
|
55
55
|
mcpServerUrl?: string;
|
|
56
56
|
}
|
|
57
|
+
interface ApiHandler {
|
|
58
|
+
/** Proxies chat messages to the WaniWani API */
|
|
59
|
+
handleChat: (request: Request) => Promise<Response>;
|
|
60
|
+
/** Serves MCP resource content (HTML widgets) */
|
|
61
|
+
handleResource: (url: URL) => Promise<Response>;
|
|
62
|
+
/** Routes GET sub-paths (e.g. /resource) */
|
|
63
|
+
routeGet: (request: Request) => Promise<Response>;
|
|
64
|
+
}
|
|
57
65
|
|
|
58
|
-
export { type
|
|
66
|
+
export { type ApiHandler, type ApiHandlerOptions, type BeforeRequestContext, type BeforeRequestResult, WaniWaniError };
|
package/dist/chat/styles.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
|
|
2
|
-
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-content:""}}}@layer theme{:root,:host{--font-sans:system-ui,-apple-system,"Segoe UI",sans-serif;--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-100:oklch(93.6% .032 17.717);--color-red-200:oklch(88.5% .062 18.334);--color-red-400:oklch(70.4% .191 22.216);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-red-800:oklch(44.4% .177 26.899);--color-emerald-400:oklch(76.5% .177 163.223);--color-emerald-500:oklch(69.6% .17 162.48);--color-teal-400:oklch(77.7% .152 181.912);--color-cyan-400:oklch(78.9% .154 211.53);--color-blue-400:oklch(70.7% .165 254.624);--color-indigo-400:oklch(67.3% .182 276.935);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-400:oklch(70.4% .04 256.788);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-2xl:42rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height:calc(1.5/1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25/1.875);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--tracking-wider:.05em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--radius-3xl:1.5rem;--ease-out:cubic-bezier(0,0,.2,1);--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-spin:spin 1s linear infinite;--animate-ping:ping 1s cubic-bezier(0,0,.2,1)infinite;--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--animate-bounce:bounce 1s infinite;--blur-sm:8px;--blur-xl:24px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius:16px;--color-background:#fff;--color-foreground:#1f2937;--color-primary:#6366f1;--color-primary-foreground:#1f2937;--color-muted:#f1f5f9;--color-muted-foreground:#6b7280;--color-border:#e5e7eb;--color-input:#f9fafb;--color-accent:#f3f4f6;--color-accent-foreground:#1f2937;--color-user-bubble:#f4f4f4;--color-status:#22c55e;--color-tool-card:#f4f4f5}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing)*0)}.top-0\.5{top:calc(var(--spacing)*.5)}.top-4{top:calc(var(--spacing)*4)}.top-full{top:100%}.right-0{right:calc(var(--spacing)*0)}.right-2{right:calc(var(--spacing)*2)}.right-4{right:calc(var(--spacing)*4)}.bottom-0{bottom:calc(var(--spacing)*0)}.bottom-0\.5{bottom:calc(var(--spacing)*.5)}.bottom-1{bottom:calc(var(--spacing)*1)}.bottom-2{bottom:calc(var(--spacing)*2)}.bottom-4{bottom:calc(var(--spacing)*4)}.bottom-14{bottom:calc(var(--spacing)*14)}.left-0{left:calc(var(--spacing)*0)}.left-2{left:calc(var(--spacing)*2)}.left-4{left:calc(var(--spacing)*4)}.left-\[50\%\]{left:50%}.z-10{z-index:10}.z-50{z-index:50}.z-\[9998\]{z-index:9998}.z-\[9999\]{z-index:9999}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mx-4{margin-inline:calc(var(--spacing)*4)}.my-4{margin-block:calc(var(--spacing)*4)}.my-6{margin-block:calc(var(--spacing)*6)}.mt-0\.5{margin-top:calc(var(--spacing)*.5)}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-1\.5{margin-top:calc(var(--spacing)*1.5)}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-6{margin-top:calc(var(--spacing)*6)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.list-item{display:list-item}.table{display:table}.table-cell{display:table-cell}.table-row{display:table-row}.field-sizing-content{field-sizing:content}.size-2{width:calc(var(--spacing)*2);height:calc(var(--spacing)*2)}.size-2\.5{width:calc(var(--spacing)*2.5);height:calc(var(--spacing)*2.5)}.size-3{width:calc(var(--spacing)*3);height:calc(var(--spacing)*3)}.size-3\.5{width:calc(var(--spacing)*3.5);height:calc(var(--spacing)*3.5)}.size-4{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.size-5{width:calc(var(--spacing)*5);height:calc(var(--spacing)*5)}.size-7{width:calc(var(--spacing)*7);height:calc(var(--spacing)*7)}.size-8{width:calc(var(--spacing)*8);height:calc(var(--spacing)*8)}.size-9{width:calc(var(--spacing)*9);height:calc(var(--spacing)*9)}.size-full{width:100%;height:100%}.h-3{height:calc(var(--spacing)*3)}.h-3\.5{height:calc(var(--spacing)*3.5)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-8{height:calc(var(--spacing)*8)}.h-9{height:calc(var(--spacing)*9)}.h-11{height:calc(var(--spacing)*11)}.h-16{height:calc(var(--spacing)*16)}.h-\[46px\]{height:46px}.h-auto{height:auto}.h-full{height:100%}.max-h-0{max-height:calc(var(--spacing)*0)}.max-h-32{max-height:calc(var(--spacing)*32)}.max-h-48{max-height:calc(var(--spacing)*48)}.min-h-0{min-height:calc(var(--spacing)*0)}.min-h-16{min-height:calc(var(--spacing)*16)}.min-h-28{min-height:calc(var(--spacing)*28)}.min-h-\[120px\]{min-height:120px}.min-h-\[160px\]{min-height:160px}.min-h-\[200px\]{min-height:200px}.min-h-screen{min-height:100vh}.w-3{width:calc(var(--spacing)*3)}.w-3\.5{width:calc(var(--spacing)*3.5)}.w-4{width:calc(var(--spacing)*4)}.w-5{width:calc(var(--spacing)*5)}.w-8{width:calc(var(--spacing)*8)}.w-11{width:calc(var(--spacing)*11)}.w-16{width:calc(var(--spacing)*16)}.w-80{width:calc(var(--spacing)*80)}.w-fit{width:fit-content}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-24{max-width:calc(var(--spacing)*24)}.max-w-32{max-width:calc(var(--spacing)*32)}.max-w-\[95\%\]{max-width:95%}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-\[120px\]{min-width:120px}.flex-1{flex:1}.shrink-0{flex-shrink:0}.border-collapse{border-collapse:collapse}.origin-center{transform-origin:50%}.translate-x-\[-50\%\]{--tw-translate-x:-50%;translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-y-0{--tw-translate-y:calc(var(--spacing)*0);translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-y-2{--tw-translate-y:calc(var(--spacing)*2);translate:var(--tw-translate-x)var(--tw-translate-y)}.scale-110{--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x)var(--tw-scale-y)}.rotate-90{rotate:90deg}.rotate-180{rotate:180deg}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.animate-\[shimmer_1\.5s_ease-in-out_infinite\]{animation:1.5s ease-in-out infinite shimmer}.animate-bounce{animation:var(--animate-bounce)}.animate-ping{animation:var(--animate-ping)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-pointer{cursor:pointer}.resize{resize:both}.resize-none{resize:none}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.appearance-none{appearance:none}.grid-rows-\[0fr\]{grid-template-rows:0fr}.grid-rows-\[1fr\]{grid-template-rows:1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-8{gap:calc(var(--spacing)*8)}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*5)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*5)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-x-2>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*2)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-x-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px*var(--tw-divide-y-reverse));border-bottom-width:calc(1px*calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-border>:not(:last-child)){border-color:var(--color-border)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-hidden{overflow-y:hidden}.rounded{border-radius:var(--radius)}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\[var\(--ww-radius\)\]{border-radius:var(--ww-radius)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-none{border-radius:0}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-\[\#414141\]{border-color:#414141}.border-\[\#424242\]{border-color:#424242}.border-blue-400\/20{border-color:#54a2ff33}@supports (color:color-mix(in lab, red, red)){.border-blue-400\/20{border-color:color-mix(in oklab,var(--color-blue-400)20%,transparent)}}.border-border{border-color:var(--color-border)}.border-current{border-color:currentColor}.border-muted-foreground\/30{border-color:#6b72804d}@supports (color:color-mix(in lab, red, red)){.border-muted-foreground\/30{border-color:color-mix(in oklab,var(--color-muted-foreground)30%,transparent)}}.border-red-200{border-color:var(--color-red-200)}.bg-\[\#2f2f2f\]{background-color:#2f2f2f}.bg-\[\#212121\]{background-color:#212121}.bg-\[\#424242\]{background-color:#424242}.bg-background{background-color:var(--color-background)}.bg-background\/20{background-color:#fff3}@supports (color:color-mix(in lab, red, red)){.bg-background\/20{background-color:color-mix(in oklab,var(--color-background)20%,transparent)}}.bg-background\/50{background-color:#ffffff80}@supports (color:color-mix(in lab, red, red)){.bg-background\/50{background-color:color-mix(in oklab,var(--color-background)50%,transparent)}}.bg-background\/80{background-color:#fffc}@supports (color:color-mix(in lab, red, red)){.bg-background\/80{background-color:color-mix(in oklab,var(--color-background)80%,transparent)}}.bg-background\/90{background-color:#ffffffe6}@supports (color:color-mix(in lab, red, red)){.bg-background\/90{background-color:color-mix(in oklab,var(--color-background)90%,transparent)}}.bg-background\/95{background-color:#fffffff2}@supports (color:color-mix(in lab, red, red)){.bg-background\/95{background-color:color-mix(in oklab,var(--color-background)95%,transparent)}}.bg-black\/10{background-color:#0000001a}@supports (color:color-mix(in lab, red, red)){.bg-black\/10{background-color:color-mix(in oklab,var(--color-black)10%,transparent)}}.bg-emerald-500\/20{background-color:#00bb7f33}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/20{background-color:color-mix(in oklab,var(--color-emerald-500)20%,transparent)}}.bg-foreground{background-color:var(--color-foreground)}.bg-gray-500\/20{background-color:#6a728233}@supports (color:color-mix(in lab, red, red)){.bg-gray-500\/20{background-color:color-mix(in oklab,var(--color-gray-500)20%,transparent)}}.bg-muted{background-color:var(--color-muted)}.bg-muted-foreground\/60{background-color:#6b728099}@supports (color:color-mix(in lab, red, red)){.bg-muted-foreground\/60{background-color:color-mix(in oklab,var(--color-muted-foreground)60%,transparent)}}.bg-muted\/40{background-color:#f1f5f966}@supports (color:color-mix(in lab, red, red)){.bg-muted\/40{background-color:color-mix(in oklab,var(--color-muted)40%,transparent)}}.bg-muted\/80{background-color:#f1f5f9cc}@supports (color:color-mix(in lab, red, red)){.bg-muted\/80{background-color:color-mix(in oklab,var(--color-muted)80%,transparent)}}.bg-primary{background-color:var(--color-primary)}.bg-red-50{background-color:var(--color-red-50)}.bg-red-100{background-color:var(--color-red-100)}.bg-status{background-color:var(--color-status)}.bg-tool-card{background-color:var(--color-tool-card)}.bg-transparent{background-color:#0000}.bg-gradient-to-r{--tw-gradient-position:to right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-blue-400{--tw-gradient-from:var(--color-blue-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-cyan-400{--tw-gradient-from:var(--color-cyan-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-slate-400{--tw-gradient-from:var(--color-slate-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-teal-400{--tw-gradient-from:var(--color-teal-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.via-slate-200{--tw-gradient-via:var(--color-slate-200);--tw-gradient-via-stops:var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-via)var(--tw-gradient-via-position),var(--tw-gradient-to)var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.to-cyan-400{--tw-gradient-to:var(--color-cyan-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-emerald-400{--tw-gradient-to:var(--color-emerald-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-slate-400{--tw-gradient-to:var(--color-slate-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-teal-400{--tw-gradient-to:var(--color-teal-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.bg-\[length\:200\%_100\%\]{background-size:200% 100%}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.object-cover{object-fit:cover}.p-0\.5{padding:calc(var(--spacing)*.5)}.p-1{padding:calc(var(--spacing)*1)}.p-1\.5{padding:calc(var(--spacing)*1.5)}.p-2{padding:calc(var(--spacing)*2)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-6{padding:calc(var(--spacing)*6)}.p-8{padding:calc(var(--spacing)*8)}.px-1\.5{padding-inline:calc(var(--spacing)*1.5)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-2\.5{padding-block:calc(var(--spacing)*2.5)}.py-3{padding-block:calc(var(--spacing)*3)}.py-12{padding-block:calc(var(--spacing)*12)}.pt-2\.5{padding-top:calc(var(--spacing)*2.5)}.pt-3{padding-top:calc(var(--spacing)*3)}.pb-1\.5{padding-bottom:calc(var(--spacing)*1.5)}.pb-3{padding-bottom:calc(var(--spacing)*3)}.pl-4{padding-left:calc(var(--spacing)*4)}.text-center{text-align:center}.text-left{text-align:left}.font-\[\'Inter\'\,_system-ui\,_sans-serif\]{font-family:Inter,system-ui,sans-serif}.font-\[family-name\:var\(--ww-font\)\]{font-family:var(--ww-font)}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-words{overflow-wrap:break-word}.wrap-anywhere{overflow-wrap:anywhere}.break-all{word-break:break-all}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-background{color:var(--color-background)}.text-emerald-400{color:var(--color-emerald-400)}.text-foreground{color:var(--color-foreground)}.text-foreground\/80{color:#1f2937cc}@supports (color:color-mix(in lab, red, red)){.text-foreground\/80{color:color-mix(in oklab,var(--color-foreground)80%,transparent)}}.text-gray-200{color:var(--color-gray-200)}.text-gray-300{color:var(--color-gray-300)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-indigo-400{color:var(--color-indigo-400)}.text-muted-foreground{color:var(--color-muted-foreground)}.text-primary{color:var(--color-primary)}.text-primary-foreground{color:var(--color-primary-foreground)}.text-red-400{color:var(--color-red-400)}.text-red-600{color:var(--color-red-600)}.text-red-700{color:var(--color-red-700)}.text-red-800{color:var(--color-red-800)}.text-transparent{color:#0000}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.italic{font-style:italic}.underline{text-decoration-line:underline}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,)}.backdrop-blur-xl{--tw-backdrop-blur:blur(var(--blur-xl));-webkit-backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[grid-template-rows\,opacity\]{transition-property:grid-template-rows,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.outline-none{--tw-outline-style:none;outline-style:none}.\[animation-delay\:-0\.3s\]{animation-delay:-.3s}.\[animation-delay\:-0\.15s\]{animation-delay:-.15s}.\[counter-increment\:line_0\]{counter-increment:line 0}.\[counter-reset\:line\]{counter-reset:line}@media (hover:hover){.group-hover\:block:is(:where(.group):hover *){display:block}.group-hover\:text-white:is(:where(.group):hover *){color:var(--color-white)}.group-hover\:opacity-0:is(:where(.group):hover *){opacity:0}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.group-\[\.is-assistant\]\:text-foreground:is(:where(.group).is-assistant *){color:var(--color-foreground)}.group-\[\.is-user\]\:ml-auto:is(:where(.group).is-user *){margin-left:auto}.group-\[\.is-user\]\:rounded-lg:is(:where(.group).is-user *){border-radius:var(--radius-lg)}.group-\[\.is-user\]\:bg-user-bubble:is(:where(.group).is-user *){background-color:var(--color-user-bubble)}.group-\[\.is-user\]\:px-4:is(:where(.group).is-user *){padding-inline:calc(var(--spacing)*4)}.group-\[\.is-user\]\:py-3:is(:where(.group).is-user *){padding-block:calc(var(--spacing)*3)}.group-\[\.is-user\]\:text-primary-foreground:is(:where(.group).is-user *){color:var(--color-primary-foreground)}.placeholder\:text-muted-foreground::placeholder{color:var(--color-muted-foreground)}.before\:mr-4:before{content:var(--tw-content);margin-right:calc(var(--spacing)*4)}.before\:inline-block:before{content:var(--tw-content);display:inline-block}.before\:w-6:before{content:var(--tw-content);width:calc(var(--spacing)*6)}.before\:text-right:before{content:var(--tw-content);text-align:right}.before\:font-mono:before{content:var(--tw-content);font-family:var(--font-mono)}.before\:text-\[13px\]:before{content:var(--tw-content);font-size:13px}.before\:text-muted-foreground\/50:before{content:var(--tw-content);color:#6b728080}@supports (color:color-mix(in lab, red, red)){.before\:text-muted-foreground\/50:before{color:color-mix(in oklab,var(--color-muted-foreground)50%,transparent)}}.before\:content-\[counter\(line\)\]:before{--tw-content:counter(line);content:var(--tw-content)}.before\:select-none:before{content:var(--tw-content);-webkit-user-select:none;user-select:none}.before\:\[counter-increment\:line\]:before{content:var(--tw-content);counter-increment:line}:is(.\*\:first\:mt-0>*):first-child{margin-top:calc(var(--spacing)*0)}:is(.\*\:last\:mb-0>*):last-child{margin-bottom:calc(var(--spacing)*0)}:is(.\*\:last\:after\:inline>*):last-child:after{content:var(--tw-content);display:inline}:is(.\*\:last\:after\:align-baseline>*):last-child:after{content:var(--tw-content);vertical-align:baseline}:is(.\*\:last\:after\:content-\(--streamdown-caret\)>*):last-child:after{--tw-content:var(--streamdown-caret);content:var(--tw-content)}@media (hover:hover){.hover\:scale-105:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x)var(--tw-scale-y)}.hover\:bg-accent:hover{background-color:var(--color-accent)}.hover\:bg-background:hover{background-color:var(--color-background)}.hover\:bg-foreground:hover{background-color:var(--color-foreground)}.hover\:bg-muted:hover{background-color:var(--color-muted)}.hover\:bg-muted\/40:hover{background-color:#f1f5f966}@supports (color:color-mix(in lab, red, red)){.hover\:bg-muted\/40:hover{background-color:color-mix(in oklab,var(--color-muted)40%,transparent)}}.hover\:bg-primary\/90:hover{background-color:#6366f1e6}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--color-primary)90%,transparent)}}.hover\:bg-white\/5:hover{background-color:#ffffff0d}@supports (color:color-mix(in lab, red, red)){.hover\:bg-white\/5:hover{background-color:color-mix(in oklab,var(--color-white)5%,transparent)}}.hover\:text-accent-foreground:hover{color:var(--color-accent-foreground)}.hover\:text-foreground:hover{color:var(--color-foreground)}.hover\:text-gray-200:hover{color:var(--color-gray-200)}.hover\:text-gray-300:hover{color:var(--color-gray-300)}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.active\:scale-95:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x)var(--tw-scale-y)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width:40rem){.sm\:rounded-3xl{border-radius:var(--radius-3xl)}}@media (prefers-color-scheme:dark){.dark\:bg-\(--shiki-dark-bg\)\!{background-color:var(--shiki-dark-bg)!important}.dark\:text-\(--shiki-dark\)\!{color:var(--shiki-dark)!important}}.\[\&_svg\]\:h-auto svg{height:auto}.\[\&_svg\]\:w-auto svg{width:auto}.\[\&\>\*\:first-child\]\:mt-0>:first-child{margin-top:calc(var(--spacing)*0)}.\[\&\>\*\:last-child\]\:mb-0>:last-child{margin-bottom:calc(var(--spacing)*0)}.\[\&\>p\]\:inline>p{display:inline}li .\[li_\&\]\:pl-6{padding-left:calc(var(--spacing)*6)}}@keyframes ww-fade-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes ww-fade-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-4px)}}@keyframes ww-pulse{0%,80%,to{opacity:.3;transform:scale(.8)}40%{opacity:1;transform:scale(1)}}[data-waniwani-chat]{--color-background:var(--ww-bg);--color-foreground:var(--ww-text);--color-primary:var(--ww-primary);--color-primary-foreground:var(--ww-primary-fg);--color-muted-foreground:var(--ww-muted);--color-border:var(--ww-border);--color-input:var(--ww-input-bg);--color-accent:var(--ww-assistant-bubble);--color-accent-foreground:var(--ww-text);--color-user-bubble:var(--ww-user-bubble);--color-card:var(--ww-bg);--color-card-foreground:var(--ww-text);--color-card-header:var(--ww-header-bg);--color-card-header-foreground:var(--ww-header-text);--color-status:var(--ww-status);--color-tool-card:var(--ww-tool-card);--radius:var(--ww-radius);--font-sans:var(--ww-font)}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@keyframes spin{to{transform:rotate(360deg)}}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}}@keyframes bounce{0%,to{animation-timing-function:cubic-bezier(.8,0,1,1);transform:translateY(-25%)}50%{animation-timing-function:cubic-bezier(0,0,.2,1);transform:none}}
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:system-ui,-apple-system,"Segoe UI",sans-serif;--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-400:oklch(70.4% .191 22.216);--color-emerald-400:oklch(76.5% .177 163.223);--color-emerald-500:oklch(69.6% .17 162.48);--color-teal-400:oklch(77.7% .152 181.912);--color-cyan-400:oklch(78.9% .154 211.53);--color-blue-400:oklch(70.7% .165 254.624);--color-indigo-400:oklch(67.3% .182 276.935);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-400:oklch(70.4% .04 256.788);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-2xl:42rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height:calc(1.5/1);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25/1.875);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--tracking-wider:.05em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--radius-3xl:1.5rem;--ease-out:cubic-bezier(0,0,.2,1);--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-spin:spin 1s linear infinite;--animate-ping:ping 1s cubic-bezier(0,0,.2,1)infinite;--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--animate-bounce:bounce 1s infinite;--blur-xl:24px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius:16px;--color-background:#fff;--color-foreground:#1f2937;--color-primary:#6366f1;--color-primary-foreground:#1f2937;--color-muted:#f1f5f9;--color-muted-foreground:#6b7280;--color-border:#e5e7eb;--color-input:#f9fafb;--color-accent:#f3f4f6;--color-accent-foreground:#1f2937;--color-user-bubble:#f4f4f4;--color-status:#22c55e;--color-tool-card:#f4f4f5}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing)*0)}.top-0\.5{top:calc(var(--spacing)*.5)}.right-0{right:calc(var(--spacing)*0)}.right-4{right:calc(var(--spacing)*4)}.bottom-0{bottom:calc(var(--spacing)*0)}.bottom-0\.5{bottom:calc(var(--spacing)*.5)}.bottom-1{bottom:calc(var(--spacing)*1)}.bottom-4{bottom:calc(var(--spacing)*4)}.bottom-14{bottom:calc(var(--spacing)*14)}.left-0{left:calc(var(--spacing)*0)}.left-\[50\%\]{left:50%}.z-10{z-index:10}.z-\[9998\]{z-index:9998}.z-\[9999\]{z-index:9999}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mx-4{margin-inline:calc(var(--spacing)*4)}.mt-0\.5{margin-top:calc(var(--spacing)*.5)}.mt-1\.5{margin-top:calc(var(--spacing)*1.5)}.mt-2{margin-top:calc(var(--spacing)*2)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.table{display:table}.field-sizing-content{field-sizing:content}.size-2{width:calc(var(--spacing)*2);height:calc(var(--spacing)*2)}.size-2\.5{width:calc(var(--spacing)*2.5);height:calc(var(--spacing)*2.5)}.size-3{width:calc(var(--spacing)*3);height:calc(var(--spacing)*3)}.size-3\.5{width:calc(var(--spacing)*3.5);height:calc(var(--spacing)*3.5)}.size-4{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.size-5{width:calc(var(--spacing)*5);height:calc(var(--spacing)*5)}.size-7{width:calc(var(--spacing)*7);height:calc(var(--spacing)*7)}.size-8{width:calc(var(--spacing)*8);height:calc(var(--spacing)*8)}.size-9{width:calc(var(--spacing)*9);height:calc(var(--spacing)*9)}.size-full{width:100%;height:100%}.h-3{height:calc(var(--spacing)*3)}.h-3\.5{height:calc(var(--spacing)*3.5)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-7{height:calc(var(--spacing)*7)}.h-8{height:calc(var(--spacing)*8)}.h-9{height:calc(var(--spacing)*9)}.h-11{height:calc(var(--spacing)*11)}.h-16{height:calc(var(--spacing)*16)}.h-auto{height:auto}.h-full{height:100%}.max-h-0{max-height:calc(var(--spacing)*0)}.max-h-48{max-height:calc(var(--spacing)*48)}.min-h-0{min-height:calc(var(--spacing)*0)}.min-h-16{min-height:calc(var(--spacing)*16)}.min-h-\[120px\]{min-height:120px}.min-h-\[160px\]{min-height:160px}.min-h-screen{min-height:100vh}.w-3{width:calc(var(--spacing)*3)}.w-3\.5{width:calc(var(--spacing)*3.5)}.w-4{width:calc(var(--spacing)*4)}.w-5{width:calc(var(--spacing)*5)}.w-8{width:calc(var(--spacing)*8)}.w-11{width:calc(var(--spacing)*11)}.w-16{width:calc(var(--spacing)*16)}.w-80{width:calc(var(--spacing)*80)}.w-fit{width:fit-content}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-24{max-width:calc(var(--spacing)*24)}.max-w-32{max-width:calc(var(--spacing)*32)}.max-w-\[95\%\]{max-width:95%}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:calc(var(--spacing)*0)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.translate-x-\[-50\%\]{--tw-translate-x:-50%;translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-y-0{--tw-translate-y:calc(var(--spacing)*0);translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-y-2{--tw-translate-y:calc(var(--spacing)*2);translate:var(--tw-translate-x)var(--tw-translate-y)}.scale-110{--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x)var(--tw-scale-y)}.rotate-90{rotate:90deg}.rotate-180{rotate:180deg}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.animate-\[shimmer_1\.5s_ease-in-out_infinite\]{animation:1.5s ease-in-out infinite shimmer}.animate-\[ww-fade-in_0\.2s_ease-out_both\]{animation:.2s ease-out both ww-fade-in}.animate-bounce{animation:var(--animate-bounce)}.animate-ping{animation:var(--animate-ping)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-pointer{cursor:pointer}.resize{resize:both}.resize-none{resize:none}.grid-rows-\[0fr\]{grid-template-rows:0fr}.grid-rows-\[1fr\]{grid-template-rows:1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-8{gap:calc(var(--spacing)*8)}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*5)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*5)*calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-hidden{overflow-y:hidden}.rounded{border-radius:var(--radius)}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\[var\(--ww-radius\)\]{border-radius:var(--ww-radius)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-none{border-radius:0}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-\[\#414141\]{border-color:#414141}.border-\[\#424242\]{border-color:#424242}.border-blue-400\/20{border-color:#54a2ff33}@supports (color:color-mix(in lab, red, red)){.border-blue-400\/20{border-color:color-mix(in oklab,var(--color-blue-400)20%,transparent)}}.border-border{border-color:var(--color-border)}.bg-\[\#2f2f2f\]{background-color:#2f2f2f}.bg-\[\#212121\]{background-color:#212121}.bg-\[\#424242\]{background-color:#424242}.bg-accent{background-color:var(--color-accent)}.bg-background{background-color:var(--color-background)}.bg-background\/20{background-color:#fff3}@supports (color:color-mix(in lab, red, red)){.bg-background\/20{background-color:color-mix(in oklab,var(--color-background)20%,transparent)}}.bg-background\/80{background-color:#fffc}@supports (color:color-mix(in lab, red, red)){.bg-background\/80{background-color:color-mix(in oklab,var(--color-background)80%,transparent)}}.bg-emerald-500\/20{background-color:#00bb7f33}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/20{background-color:color-mix(in oklab,var(--color-emerald-500)20%,transparent)}}.bg-foreground{background-color:var(--color-foreground)}.bg-gray-500\/20{background-color:#6a728233}@supports (color:color-mix(in lab, red, red)){.bg-gray-500\/20{background-color:color-mix(in oklab,var(--color-gray-500)20%,transparent)}}.bg-muted{background-color:var(--color-muted)}.bg-muted-foreground\/60{background-color:#6b728099}@supports (color:color-mix(in lab, red, red)){.bg-muted-foreground\/60{background-color:color-mix(in oklab,var(--color-muted-foreground)60%,transparent)}}.bg-muted\/50{background-color:#f1f5f980}@supports (color:color-mix(in lab, red, red)){.bg-muted\/50{background-color:color-mix(in oklab,var(--color-muted)50%,transparent)}}.bg-primary{background-color:var(--color-primary)}.bg-status{background-color:var(--color-status)}.bg-tool-card{background-color:var(--color-tool-card)}.bg-transparent{background-color:#0000}.bg-gradient-to-r{--tw-gradient-position:to right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-blue-400{--tw-gradient-from:var(--color-blue-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-cyan-400{--tw-gradient-from:var(--color-cyan-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-slate-400{--tw-gradient-from:var(--color-slate-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-teal-400{--tw-gradient-from:var(--color-teal-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.via-slate-200{--tw-gradient-via:var(--color-slate-200);--tw-gradient-via-stops:var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-via)var(--tw-gradient-via-position),var(--tw-gradient-to)var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.to-cyan-400{--tw-gradient-to:var(--color-cyan-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-emerald-400{--tw-gradient-to:var(--color-emerald-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-slate-400{--tw-gradient-to:var(--color-slate-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-teal-400{--tw-gradient-to:var(--color-teal-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.bg-\[length\:200\%_100\%\]{background-size:200% 100%}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.object-cover{object-fit:cover}.p-0\.5{padding:calc(var(--spacing)*.5)}.p-1{padding:calc(var(--spacing)*1)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-8{padding:calc(var(--spacing)*8)}.px-1\.5{padding-inline:calc(var(--spacing)*1.5)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-2\.5{padding-block:calc(var(--spacing)*2.5)}.py-3{padding-block:calc(var(--spacing)*3)}.py-12{padding-block:calc(var(--spacing)*12)}.pt-2\.5{padding-top:calc(var(--spacing)*2.5)}.pt-3{padding-top:calc(var(--spacing)*3)}.pb-1\.5{padding-bottom:calc(var(--spacing)*1.5)}.pb-3{padding-bottom:calc(var(--spacing)*3)}.text-center{text-align:center}.text-left{text-align:left}.font-\[\'Inter\'\,_system-ui\,_sans-serif\]{font-family:Inter,system-ui,sans-serif}.font-\[family-name\:var\(--ww-font\)\]{font-family:var(--ww-font)}.font-mono{font-family:var(--font-mono)}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-pre-wrap{white-space:pre-wrap}.text-background{color:var(--color-background)}.text-emerald-400{color:var(--color-emerald-400)}.text-foreground{color:var(--color-foreground)}.text-foreground\/80{color:#1f2937cc}@supports (color:color-mix(in lab, red, red)){.text-foreground\/80{color:color-mix(in oklab,var(--color-foreground)80%,transparent)}}.text-gray-200{color:var(--color-gray-200)}.text-gray-300{color:var(--color-gray-300)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-indigo-400{color:var(--color-indigo-400)}.text-muted-foreground{color:var(--color-muted-foreground)}.text-primary{color:var(--color-primary)}.text-primary-foreground{color:var(--color-primary-foreground)}.text-red-400{color:var(--color-red-400)}.text-transparent{color:#0000}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.backdrop-blur-xl{--tw-backdrop-blur:blur(var(--blur-xl));-webkit-backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[grid-template-rows\,opacity\]{transition-property:grid-template-rows,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.outline-none{--tw-outline-style:none;outline-style:none}.\[animation-delay\:-0\.3s\]{animation-delay:-.3s}.\[animation-delay\:-0\.15s\]{animation-delay:-.15s}@media (hover:hover){.group-hover\:text-white:is(:where(.group):hover *){color:var(--color-white)}.group-hover\:opacity-0:is(:where(.group):hover *){opacity:0}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.group-\[\.is-assistant\]\:text-foreground:is(:where(.group).is-assistant *){color:var(--color-foreground)}.group-\[\.is-user\]\:ml-auto:is(:where(.group).is-user *){margin-left:auto}.group-\[\.is-user\]\:rounded-lg:is(:where(.group).is-user *){border-radius:var(--radius-lg)}.group-\[\.is-user\]\:bg-user-bubble:is(:where(.group).is-user *){background-color:var(--color-user-bubble)}.group-\[\.is-user\]\:px-4:is(:where(.group).is-user *){padding-inline:calc(var(--spacing)*4)}.group-\[\.is-user\]\:py-3:is(:where(.group).is-user *){padding-block:calc(var(--spacing)*3)}.group-\[\.is-user\]\:text-primary-foreground:is(:where(.group).is-user *){color:var(--color-primary-foreground)}.placeholder\:text-muted-foreground::placeholder{color:var(--color-muted-foreground)}@media (hover:hover){.hover\:scale-105:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x)var(--tw-scale-y)}.hover\:border-primary\/30:hover{border-color:#6366f14d}@supports (color:color-mix(in lab, red, red)){.hover\:border-primary\/30:hover{border-color:color-mix(in oklab,var(--color-primary)30%,transparent)}}.hover\:bg-accent:hover{background-color:var(--color-accent)}.hover\:bg-foreground:hover{background-color:var(--color-foreground)}.hover\:bg-primary\/90:hover{background-color:#6366f1e6}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--color-primary)90%,transparent)}}.hover\:bg-white\/5:hover{background-color:#ffffff0d}@supports (color:color-mix(in lab, red, red)){.hover\:bg-white\/5:hover{background-color:color-mix(in oklab,var(--color-white)5%,transparent)}}.hover\:text-accent-foreground:hover{color:var(--color-accent-foreground)}.hover\:text-foreground:hover{color:var(--color-foreground)}.hover\:text-gray-200:hover{color:var(--color-gray-200)}.hover\:text-gray-300:hover{color:var(--color-gray-300)}.hover\:underline:hover{text-decoration-line:underline}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.active\:scale-95:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x)var(--tw-scale-y)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width:40rem){.sm\:rounded-3xl{border-radius:var(--radius-3xl)}}.\[\&\>\*\:first-child\]\:mt-0>:first-child{margin-top:calc(var(--spacing)*0)}.\[\&\>\*\:last-child\]\:mb-0>:last-child{margin-bottom:calc(var(--spacing)*0)}}@keyframes ww-fade-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes ww-fade-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-4px)}}@keyframes ww-pulse{0%,80%,to{opacity:.3;transform:scale(.8)}40%{opacity:1;transform:scale(1)}}[data-waniwani-chat]{--color-background:var(--ww-bg);--color-foreground:var(--ww-text);--color-primary:var(--ww-primary);--color-primary-foreground:var(--ww-primary-fg);--color-muted-foreground:var(--ww-muted);--color-border:var(--ww-border);--color-input:var(--ww-input-bg);--color-accent:var(--ww-assistant-bubble);--color-accent-foreground:var(--ww-text);--color-user-bubble:var(--ww-user-bubble);--color-card:var(--ww-bg);--color-card-foreground:var(--ww-text);--color-card-header:var(--ww-header-bg);--color-card-header-foreground:var(--ww-header-text);--color-status:var(--ww-status);--color-tool-card:var(--ww-tool-card);--radius:var(--ww-radius);--font-sans:var(--ww-font)}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}}@keyframes bounce{0%,to{animation-timing-function:cubic-bezier(.8,0,1,1);transform:translateY(-25%)}50%{animation-timing-function:cubic-bezier(0,0,.2,1);transform:none}}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
function e(){return typeof window<"u"&&"openai"in window?"openai":"mcp-apps"}function n(){return e()==="openai"}function p(){return e()==="mcp-apps"}export{e as a,n as b,p as c};
|
|
3
|
-
//# sourceMappingURL=chunk-
|
|
3
|
+
//# sourceMappingURL=chunk-DGSC74SV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp/react/widgets/platform.ts"],"sourcesContent":["/**\n * Widget platform types\n */\nexport type WidgetPlatform = \"openai\" | \"mcp-apps\";\n\n/**\n * Detects which platform the widget is running on.\n *\n * OpenAI injects a global `window.openai` object.\n * MCP Apps runs in a sandboxed iframe and uses postMessage.\n */\nexport function detectPlatform(): WidgetPlatform {\n\tif (typeof window !== \"undefined\" && \"openai\" in window) {\n\t\treturn \"openai\";\n\t}\n\treturn \"mcp-apps\";\n}\n\n/**\n * Check if running on OpenAI platform\n */\nexport function isOpenAI(): boolean {\n\treturn detectPlatform() === \"openai\";\n}\n\n/**\n * Check if running on MCP Apps platform\n */\nexport function isMCPApps(): boolean {\n\treturn detectPlatform() === \"mcp-apps\";\n}\n"],"mappings":";AAWO,SAASA,GAAiC,CAChD,OAAI,OAAO,OAAW,KAAe,WAAY,OACzC,SAED,UACR,CAKO,SAASC,GAAoB,CACnC,OAAOD,EAAe,IAAM,QAC7B,CAKO,SAASE,GAAqB,CACpC,OAAOF,EAAe,IAAM,UAC7B","names":["detectPlatform","isOpenAI","isMCPApps"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp/react/hooks/@types.ts"],"sourcesContent":["/**\n * Source: https://github.com/openai/openai-apps-sdk-examples/tree/main/src\n */\n\nexport type OpenAIGlobals<\n\tToolInput = UnknownObject,\n\tToolOutput = UnknownObject,\n\tToolResponseMetadata = UnknownObject,\n\tWidgetState = UnknownObject,\n> = {\n\t// visuals\n\ttheme: Theme;\n\n\tuserAgent: UserAgent;\n\tlocale: string;\n\n\t// layout\n\tmaxHeight: number;\n\tdisplayMode: DisplayMode;\n\tsafeArea: SafeArea;\n\n\t// state\n\ttoolInput: ToolInput;\n\ttoolOutput: ToolOutput | null;\n\ttoolResponseMetadata: ToolResponseMetadata | null;\n\twidgetState: WidgetState | null;\n\tsetWidgetState: (state: WidgetState) => Promise<void>;\n};\n\ntype API = {\n\tcallTool: CallTool;\n\tsendFollowUpMessage: (args: { prompt: string }) => Promise<void>;\n\topenExternal(payload: { href: string }): void;\n\n\t// Layout controls\n\trequestDisplayMode: RequestDisplayMode;\n};\n\nexport type UnknownObject = Record<string, unknown>;\n\nexport type Theme = \"light\" | \"dark\";\n\nexport type SafeAreaInsets = {\n\ttop: number;\n\tbottom: number;\n\tleft: number;\n\tright: number;\n};\n\nexport type SafeArea = {\n\tinsets: SafeAreaInsets;\n};\n\nexport type DeviceType = \"mobile\" | \"tablet\" | \"desktop\" | \"unknown\";\n\nexport type UserAgent = {\n\tdevice: { type: DeviceType };\n\tcapabilities: {\n\t\thover: boolean;\n\t\ttouch: boolean;\n\t};\n};\n\n/** Display mode */\nexport type DisplayMode = \"pip\" | \"inline\" | \"fullscreen\";\nexport type RequestDisplayMode = (args: { mode: DisplayMode }) => Promise<{\n\t/**\n\t * The granted display mode. The host may reject the request.\n\t * For mobile, PiP is always coerced to fullscreen.\n\t */\n\tmode: DisplayMode;\n}>;\n\nexport type CallToolResponse = {\n\tresult: string;\n};\n\n/** Calling APIs */\nexport type CallTool = (\n\tname: string,\n\targs: Record<string, unknown>,\n) => Promise<CallToolResponse>;\n\n/** Extra events */\nexport const SET_GLOBALS_EVENT_TYPE = \"openai:set_globals\";\nexport class SetGlobalsEvent extends CustomEvent<{\n\tglobals: Partial<OpenAIGlobals>;\n}> {\n\tconstructor(detail: { globals: Partial<OpenAIGlobals> }) {\n\t\tsuper(SET_GLOBALS_EVENT_TYPE, { detail });\n\t}\n}\n\n/**\n * Global oai object injected by the web sandbox for communicating with chatgpt host page.\n */\ndeclare global {\n\tinterface Window {\n\t\topenai: API & OpenAIGlobals;\n\t\tinnerBaseUrl: string;\n\t}\n\n\tinterface WindowEventMap {\n\t\t[SET_GLOBALS_EVENT_TYPE]: SetGlobalsEvent;\n\t}\n}\n"],"mappings":";AAoFO,IAAMA,EAAyB,qBACzBC,EAAN,cAA8B,WAElC,CACF,YAAYC,EAA6C,CACxD,MAAMF,EAAwB,CAAE,OAAAE,CAAO,CAAC,CACzC,CACD","names":["SET_GLOBALS_EVENT_TYPE","SetGlobalsEvent","detail"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,60 +1,8 @@
|
|
|
1
|
-
import { UIMessage } from 'ai';
|
|
2
|
-
|
|
3
1
|
declare class WaniWaniError extends Error {
|
|
4
2
|
status: number;
|
|
5
3
|
constructor(message: string, status: number);
|
|
6
4
|
}
|
|
7
5
|
|
|
8
|
-
interface BeforeRequestContext {
|
|
9
|
-
/** The conversation messages from the client */
|
|
10
|
-
messages: UIMessage[];
|
|
11
|
-
/** Session identifier for conversation continuity */
|
|
12
|
-
sessionId?: string;
|
|
13
|
-
/** The original HTTP Request object */
|
|
14
|
-
request: Request;
|
|
15
|
-
}
|
|
16
|
-
type BeforeRequestResult = {
|
|
17
|
-
/** Override messages (e.g., filtered, augmented) */
|
|
18
|
-
messages?: UIMessage[];
|
|
19
|
-
/** Override the system prompt for this request */
|
|
20
|
-
systemPrompt?: string;
|
|
21
|
-
/** Override sessionId */
|
|
22
|
-
sessionId?: string;
|
|
23
|
-
};
|
|
24
|
-
interface ChatHandlerOptions {
|
|
25
|
-
/**
|
|
26
|
-
* Your WaniWani API key.
|
|
27
|
-
* Defaults to process.env.WANIWANI_API_KEY.
|
|
28
|
-
*/
|
|
29
|
-
apiKey?: string;
|
|
30
|
-
/**
|
|
31
|
-
* The base URL of the WaniWani API.
|
|
32
|
-
* Defaults to https://app.waniwani.ai.
|
|
33
|
-
*/
|
|
34
|
-
baseUrl?: string;
|
|
35
|
-
/**
|
|
36
|
-
* System prompt for the assistant.
|
|
37
|
-
* Can be overridden per-request via `beforeRequest`.
|
|
38
|
-
*/
|
|
39
|
-
systemPrompt?: string;
|
|
40
|
-
/**
|
|
41
|
-
* Maximum number of tool call steps. Defaults to 5.
|
|
42
|
-
*/
|
|
43
|
-
maxSteps?: number;
|
|
44
|
-
/**
|
|
45
|
-
* Hook called before each request is forwarded to the WaniWani API.
|
|
46
|
-
* - Return void to use defaults.
|
|
47
|
-
* - Return an object to override messages, systemPrompt, or sessionId.
|
|
48
|
-
* - Throw to reject the request (the error message is returned as JSON).
|
|
49
|
-
*/
|
|
50
|
-
beforeRequest?: (context: BeforeRequestContext) => Promise<BeforeRequestResult | undefined> | BeforeRequestResult | undefined;
|
|
51
|
-
/**
|
|
52
|
-
* Override the MCP server URL directly, bypassing config resolution.
|
|
53
|
-
* Useful for development/testing when pointing to a local MCP server.
|
|
54
|
-
*/
|
|
55
|
-
mcpServerUrl?: string;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
6
|
type EventType = "tool.called" | "quote.requested" | "quote.succeeded" | "quote.failed" | "link.clicked" | "purchase.completed";
|
|
59
7
|
interface ToolCalledProperties {
|
|
60
8
|
name?: string;
|
|
@@ -156,14 +104,17 @@ interface WaniWaniConfig {
|
|
|
156
104
|
*
|
|
157
105
|
* Extends with each module:
|
|
158
106
|
* - TrackingClient: track(), getOrCreateSession()
|
|
159
|
-
*
|
|
107
|
+
*
|
|
108
|
+
* Pass this client to framework adapters:
|
|
109
|
+
* - `toNextJsHandler(wani, { ... })` for Next.js route handlers
|
|
160
110
|
*/
|
|
161
111
|
interface WaniWaniClient extends TrackingClient {
|
|
162
|
-
/**
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
112
|
+
/** @internal Resolved config — used by framework adapters */
|
|
113
|
+
readonly _config: InternalConfig;
|
|
114
|
+
}
|
|
115
|
+
interface InternalConfig {
|
|
116
|
+
baseUrl: string;
|
|
117
|
+
apiKey: string | undefined;
|
|
167
118
|
}
|
|
168
119
|
|
|
169
120
|
/**
|
|
@@ -174,14 +125,14 @@ interface WaniWaniClient extends TrackingClient {
|
|
|
174
125
|
*
|
|
175
126
|
* @example
|
|
176
127
|
* ```typescript
|
|
177
|
-
* import { waniwani } from "@waniwani";
|
|
128
|
+
* import { waniwani } from "@waniwani/sdk";
|
|
129
|
+
* import { toNextJsHandler } from "@waniwani/sdk/next-js";
|
|
178
130
|
*
|
|
179
|
-
* const
|
|
131
|
+
* const wani = waniwani({ apiKey: "..." });
|
|
180
132
|
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
* toolName: "pricing"
|
|
133
|
+
* // Next.js route handler
|
|
134
|
+
* export const { GET, POST } = toNextJsHandler(wani, {
|
|
135
|
+
* chat: { systemPrompt: "You are a helpful assistant." },
|
|
185
136
|
* });
|
|
186
137
|
* ```
|
|
187
138
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var i=class extends Error{constructor(e,n){super(e);this.status=n;this.name="WaniWaniError"}};function l(r){let{baseUrl:o,apiKey:e}=r;function n(){if(!e)throw new Error("WANIWANI_API_KEY is not set")}return{async track(p){try{n();let t=await fetch(`${o}/api/mcp/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify(p)}),c=await t.json();if(!t.ok)throw new i(c.message??"Request failed",t.status);return{eventId:c.data.eventId}}catch(t){throw console.error("[WaniWani] Track error:",t),t}}}}function f(r){let o=r?.baseUrl??"https://app.waniwani.ai",e=r?.apiKey??process.env.WANIWANI_API_KEY,n={baseUrl:o,apiKey:e};return{...l(n),_config:n}}export{i as WaniWaniError,f as waniwani};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/error.ts","../src/chat/server/mcp-config-resolver.ts","../src/chat/server/chat-handler.ts","../src/tracking/index.ts","../src/waniwani.ts"],"sourcesContent":["// WaniWani SDK - Errors\n\nexport class WaniWaniError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic status: number,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"WaniWaniError\";\n\t}\n}\n","// MCP Config Resolver - Lazy-loads and caches MCP environment config\n\nimport { WaniWaniError } from \"../../error\";\n\ninterface McpEnvironmentConfig {\n\tmcpServerUrl: string;\n}\n\nconst TTL_MS = 5 * 60 * 1000; // 5 minutes\n\nexport function createMcpConfigResolver(\n\tbaseUrl: string,\n\tapiKey: string | undefined,\n) {\n\tlet cached: { config: McpEnvironmentConfig; expiresAt: number } | null = null;\n\tlet inflight: Promise<McpEnvironmentConfig> | null = null;\n\n\treturn async function resolve(): Promise<McpEnvironmentConfig> {\n\t\tif (cached && Date.now() < cached.expiresAt) {\n\t\t\treturn cached.config;\n\t\t}\n\n\t\t// Deduplicate concurrent requests (cold start scenario)\n\t\tif (inflight) {\n\t\t\treturn inflight;\n\t\t}\n\n\t\tinflight = (async () => {\n\t\t\tif (!apiKey) {\n\t\t\t\tthrow new WaniWaniError(\n\t\t\t\t\t\"WANIWANI_API_KEY is required for createChatHandler\",\n\t\t\t\t\t401,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst response = await fetch(`${baseUrl}/api/mcp/environments/config`, {\n\t\t\t\tmethod: \"GET\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${apiKey}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst body = await response.text().catch(() => \"\");\n\t\t\t\tthrow new WaniWaniError(\n\t\t\t\t\t`Failed to resolve MCP environment config: ${response.status} ${body}`,\n\t\t\t\t\tresponse.status,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst data = (await response.json()) as McpEnvironmentConfig;\n\t\t\tcached = { config: data, expiresAt: Date.now() + TTL_MS };\n\t\t\treturn data;\n\t\t})();\n\n\t\ttry {\n\t\t\treturn await inflight;\n\t\t} finally {\n\t\t\tinflight = null;\n\t\t}\n\t};\n}\n","// Chat Handler - Proxies chat requests to the WaniWani API\n\nimport { WaniWaniError } from \"../../error\";\nimport type { ChatHandlerOptions } from \"./@types\";\nimport { createMcpConfigResolver } from \"./mcp-config-resolver\";\n\n/**\n * Create a chat request handler that proxies requests to the WaniWani API.\n * The WaniWani API handles MCP tool discovery, LLM calls, and event logging.\n *\n * Returns a `(request: Request) => Promise<Response>` function compatible\n * with Next.js Route Handlers, Hono, and any framework using the Fetch API.\n *\n * @example\n * ```typescript\n * import { createChatHandler } from \"@waniwani/sdk/chat/server\";\n *\n * export const POST = createChatHandler({\n * systemPrompt: \"You are a helpful assistant.\",\n * });\n * ```\n */\nexport function createChatHandler(\n\toptions: ChatHandlerOptions = {},\n): (request: Request) => Promise<Response> {\n\tconst {\n\t\tapiKey = process.env.WANIWANI_API_KEY,\n\t\tbaseUrl = \"https://app.waniwani.ai\",\n\t\tsystemPrompt,\n\t\tmaxSteps = 5,\n\t\tbeforeRequest,\n\t\tmcpServerUrl: mcpServerUrlOverride,\n\t} = options;\n\n\tconst resolveConfig = createMcpConfigResolver(baseUrl, apiKey);\n\n\treturn async function handler(request: Request): Promise<Response> {\n\t\ttry {\n\t\t\t// 1. Parse request body\n\t\t\tconst body = await request.json();\n\t\t\tlet messages = body.messages ?? [];\n\t\t\tlet sessionId: string | undefined = body.sessionId;\n\t\t\tlet effectiveSystemPrompt = systemPrompt;\n\n\t\t\t// 2. Run beforeRequest hook\n\t\t\tif (beforeRequest) {\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await beforeRequest({\n\t\t\t\t\t\tmessages,\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\trequest,\n\t\t\t\t\t});\n\n\t\t\t\t\tif (result) {\n\t\t\t\t\t\tif (result.messages) messages = result.messages;\n\t\t\t\t\t\tif (result.systemPrompt !== undefined)\n\t\t\t\t\t\t\teffectiveSystemPrompt = result.systemPrompt;\n\t\t\t\t\t\tif (result.sessionId !== undefined) sessionId = result.sessionId;\n\t\t\t\t\t}\n\t\t\t\t} catch (hookError) {\n\t\t\t\t\tconst status =\n\t\t\t\t\t\thookError instanceof WaniWaniError ? hookError.status : 400;\n\t\t\t\t\tconst message =\n\t\t\t\t\t\thookError instanceof Error ? hookError.message : \"Request rejected\";\n\t\t\t\t\treturn Response.json({ error: message }, { status });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 3. Resolve MCP server URL\n\t\t\tconst mcpServerUrl =\n\t\t\t\tmcpServerUrlOverride ?? (await resolveConfig()).mcpServerUrl;\n\n\t\t\t// 4. Forward to WaniWani API\n\t\t\tconst response = await fetch(`${baseUrl}/api/mcp/chat`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmessages,\n\t\t\t\t\tmcpServerUrl,\n\t\t\t\t\tsessionId,\n\t\t\t\t\tsystemPrompt: effectiveSystemPrompt,\n\t\t\t\t\tmaxSteps,\n\t\t\t\t}),\n\t\t\t\tsignal: request.signal,\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errorBody = await response.text().catch(() => \"\");\n\t\t\t\treturn new Response(errorBody, {\n\t\t\t\t\tstatus: response.status,\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"Content-Type\":\n\t\t\t\t\t\t\tresponse.headers.get(\"Content-Type\") ?? \"application/json\",\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// 5. Stream the response back\n\t\t\treturn new Response(response.body, {\n\t\t\t\tstatus: response.status,\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\":\n\t\t\t\t\t\tresponse.headers.get(\"Content-Type\") ?? \"text/event-stream\",\n\t\t\t\t},\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconst message =\n\t\t\t\terror instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tconst status = error instanceof WaniWaniError ? error.status : 500;\n\n\t\t\treturn Response.json({ error: message }, { status });\n\t\t}\n\t};\n}\n","// Tracking Module\n\nimport { WaniWaniError } from \"../error.js\";\nimport type { InternalConfig } from \"../types.js\";\nimport type { TrackEvent, TrackingClient } from \"./@types.js\";\n\n// Re-export types\nexport type {\n\tEventType,\n\tLinkClickedProperties,\n\tPurchaseCompletedProperties,\n\tQuoteSucceededProperties,\n\tToolCalledProperties,\n\tTrackEvent,\n\tTrackingClient,\n} from \"./@types.js\";\n\nexport function createTrackingClient(config: InternalConfig): TrackingClient {\n\tconst { baseUrl, apiKey } = config;\n\n\tfunction checkIfApiKeyIsSet() {\n\t\tif (!apiKey) {\n\t\t\tthrow new Error(\"WANIWANI_API_KEY is not set\");\n\t\t}\n\t}\n\n\treturn {\n\t\tasync track(event: TrackEvent): Promise<{ eventId: string }> {\n\t\t\ttry {\n\t\t\t\tcheckIfApiKeyIsSet();\n\n\t\t\t\tconst response = await fetch(`${baseUrl}/api/mcp/events`, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\tAuthorization: `Bearer ${apiKey}`,\n\t\t\t\t\t},\n\t\t\t\t\tbody: JSON.stringify(event),\n\t\t\t\t});\n\n\t\t\t\tconst data = await response.json();\n\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new WaniWaniError(\n\t\t\t\t\t\tdata.message ?? \"Request failed\",\n\t\t\t\t\t\tresponse.status,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn { eventId: data.data.eventId };\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"[WaniWani] Track error:\", error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t};\n}\n","// WaniWani SDK - Main Entry\n\nimport { createChatHandler } from \"./chat/server/chat-handler.js\";\nimport { createTrackingClient } from \"./tracking/index.js\";\nimport type { WaniWaniClient, WaniWaniConfig } from \"./types.js\";\n\n/**\n * Create a WaniWani SDK client\n *\n * @param config - Configuration options\n * @returns A fully typed WaniWani client\n *\n * @example\n * ```typescript\n * import { waniwani } from \"@waniwani\";\n *\n * const client = waniwani({ apiKey: \"...\" });\n *\n * await client.track({\n * eventType: \"tool.called\",\n * sessionId: \"session-123\",\n * toolName: \"pricing\"\n * });\n * ```\n */\nexport function waniwani(config?: WaniWaniConfig): WaniWaniClient {\n\tconst baseUrl = config?.baseUrl ?? \"https://app.waniwani.ai\";\n\tconst apiKey = config?.apiKey ?? process.env.WANIWANI_API_KEY;\n\n\tconst internalConfig = { baseUrl, apiKey };\n\n\t// Compose client from modules\n\tconst tracking = createTrackingClient(internalConfig);\n\n\treturn {\n\t\t...tracking,\n\t\tcreateChatHandler: (options = {}) =>\n\t\t\tcreateChatHandler({ ...options, apiKey, baseUrl }),\n\t};\n}\n"],"mappings":"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","names":["WaniWaniError","message","status","TTL_MS","createMcpConfigResolver","baseUrl","apiKey","cached","inflight","WaniWaniError","response","body","data","createChatHandler","options","apiKey","baseUrl","systemPrompt","maxSteps","beforeRequest","mcpServerUrlOverride","resolveConfig","createMcpConfigResolver","request","body","messages","sessionId","effectiveSystemPrompt","result","hookError","status","WaniWaniError","message","mcpServerUrl","response","errorBody","error","createTrackingClient","config","baseUrl","apiKey","checkIfApiKeyIsSet","event","response","data","WaniWaniError","error","waniwani","config","baseUrl","apiKey","createTrackingClient","options","createChatHandler"]}
|
|
1
|
+
{"version":3,"sources":["../src/error.ts","../src/tracking/index.ts","../src/waniwani.ts"],"sourcesContent":["// WaniWani SDK - Errors\n\nexport class WaniWaniError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic status: number,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"WaniWaniError\";\n\t}\n}\n","// Tracking Module\n\nimport { WaniWaniError } from \"../error.js\";\nimport type { InternalConfig } from \"../types.js\";\nimport type { TrackEvent, TrackingClient } from \"./@types.js\";\n\n// Re-export types\nexport type {\n\tEventType,\n\tLinkClickedProperties,\n\tPurchaseCompletedProperties,\n\tQuoteSucceededProperties,\n\tToolCalledProperties,\n\tTrackEvent,\n\tTrackingClient,\n} from \"./@types.js\";\n\nexport function createTrackingClient(config: InternalConfig): TrackingClient {\n\tconst { baseUrl, apiKey } = config;\n\n\tfunction checkIfApiKeyIsSet() {\n\t\tif (!apiKey) {\n\t\t\tthrow new Error(\"WANIWANI_API_KEY is not set\");\n\t\t}\n\t}\n\n\treturn {\n\t\tasync track(event: TrackEvent): Promise<{ eventId: string }> {\n\t\t\ttry {\n\t\t\t\tcheckIfApiKeyIsSet();\n\n\t\t\t\tconst response = await fetch(`${baseUrl}/api/mcp/events`, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\tAuthorization: `Bearer ${apiKey}`,\n\t\t\t\t\t},\n\t\t\t\t\tbody: JSON.stringify(event),\n\t\t\t\t});\n\n\t\t\t\tconst data = await response.json();\n\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new WaniWaniError(\n\t\t\t\t\t\tdata.message ?? \"Request failed\",\n\t\t\t\t\t\tresponse.status,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn { eventId: data.data.eventId };\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"[WaniWani] Track error:\", error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t};\n}\n","// WaniWani SDK - Main Entry\n\nimport { createTrackingClient } from \"./tracking/index.js\";\nimport type { WaniWaniClient, WaniWaniConfig } from \"./types.js\";\n\n/**\n * Create a WaniWani SDK client\n *\n * @param config - Configuration options\n * @returns A fully typed WaniWani client\n *\n * @example\n * ```typescript\n * import { waniwani } from \"@waniwani/sdk\";\n * import { toNextJsHandler } from \"@waniwani/sdk/next-js\";\n *\n * const wani = waniwani({ apiKey: \"...\" });\n *\n * // Next.js route handler\n * export const { GET, POST } = toNextJsHandler(wani, {\n * chat: { systemPrompt: \"You are a helpful assistant.\" },\n * });\n * ```\n */\nexport function waniwani(config?: WaniWaniConfig): WaniWaniClient {\n\tconst baseUrl = config?.baseUrl ?? \"https://app.waniwani.ai\";\n\tconst apiKey = config?.apiKey ?? process.env.WANIWANI_API_KEY;\n\n\tconst internalConfig = { baseUrl, apiKey };\n\n\t// Compose client from modules\n\tconst tracking = createTrackingClient(internalConfig);\n\n\treturn {\n\t\t...tracking,\n\t\t_config: internalConfig,\n\t};\n}\n"],"mappings":"AAEO,IAAMA,EAAN,cAA4B,KAAM,CACxC,YACCC,EACOC,EACN,CACD,MAAMD,CAAO,EAFN,YAAAC,EAGP,KAAK,KAAO,eACb,CACD,ECOO,SAASC,EAAqBC,EAAwC,CAC5E,GAAM,CAAE,QAAAC,EAAS,OAAAC,CAAO,EAAIF,EAE5B,SAASG,GAAqB,CAC7B,GAAI,CAACD,EACJ,MAAM,IAAI,MAAM,6BAA6B,CAE/C,CAEA,MAAO,CACN,MAAM,MAAME,EAAiD,CAC5D,GAAI,CACHD,EAAmB,EAEnB,IAAME,EAAW,MAAM,MAAM,GAAGJ,CAAO,kBAAmB,CACzD,OAAQ,OACR,QAAS,CACR,eAAgB,mBAChB,cAAe,UAAUC,CAAM,EAChC,EACA,KAAM,KAAK,UAAUE,CAAK,CAC3B,CAAC,EAEKE,EAAO,MAAMD,EAAS,KAAK,EAEjC,GAAI,CAACA,EAAS,GACb,MAAM,IAAIE,EACTD,EAAK,SAAW,iBAChBD,EAAS,MACV,EAGD,MAAO,CAAE,QAASC,EAAK,KAAK,OAAQ,CACrC,OAASE,EAAO,CACf,cAAQ,MAAM,0BAA2BA,CAAK,EACxCA,CACP,CACD,CACD,CACD,CChCO,SAASC,EAASC,EAAyC,CACjE,IAAMC,EAAUD,GAAQ,SAAW,0BAC7BE,EAASF,GAAQ,QAAU,QAAQ,IAAI,iBAEvCG,EAAiB,CAAE,QAAAF,EAAS,OAAAC,CAAO,EAKzC,MAAO,CACN,GAHgBE,EAAqBD,CAAc,EAInD,QAASA,CACV,CACD","names":["WaniWaniError","message","status","createTrackingClient","config","baseUrl","apiKey","checkIfApiKeyIsSet","event","response","data","WaniWaniError","error","waniwani","config","baseUrl","apiKey","internalConfig","createTrackingClient"]}
|