vibezcheck 0.2.0 → 0.3.0

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.
@@ -1,5 +1,6 @@
1
- import { T as TokenUsage, I as InferenceCost } from '../types-CSrSmsd1.mjs';
2
- import React$1 from 'react';
1
+ import { T as TokenUsage, I as InferenceCost } from '../types-DCuzLVyc.mjs';
2
+ import * as React$1 from 'react';
3
+ import React__default from 'react';
3
4
  import 'stripe';
4
5
 
5
6
  /**
@@ -122,33 +123,84 @@ interface VibezSessionBadgeProps {
122
123
  style?: React.CSSProperties;
123
124
  }
124
125
 
125
- declare const VibezSessionContext: React$1.Context<VibezSessionContextValue | null>;
126
- declare const VibezSessionProvider: React$1.FC<VibezSessionProviderProps>;
126
+ declare const VibezSessionContext: React__default.Context<VibezSessionContextValue | null>;
127
+ declare const VibezSessionProvider: React__default.FC<VibezSessionProviderProps>;
127
128
 
128
129
  /**
129
130
  * Hook to access live session usage, cost totals, and turn recorder
131
+ */
132
+ declare function useVibezSession(): VibezSessionContextValue;
133
+ declare const useVibez: typeof useVibezSession;
134
+ interface VibezChatMessage {
135
+ id: string;
136
+ role: 'user' | 'assistant' | 'system';
137
+ content: string;
138
+ annotations?: Array<{
139
+ type: string;
140
+ reasoning?: string;
141
+ [key: string]: any;
142
+ }>;
143
+ createdAt?: Date;
144
+ }
145
+ interface UseVibezChatOptions {
146
+ api?: string;
147
+ model?: string;
148
+ customer?: string;
149
+ body?: Record<string, any>;
150
+ initialMessages?: VibezChatMessage[];
151
+ onFinish?: (message: VibezChatMessage, usage: any) => void;
152
+ onError?: (error: Error) => void;
153
+ }
154
+ /**
155
+ * Declarative, 1-line Chat Streaming Hook with automatic VibezCheck session tracking.
130
156
  *
131
157
  * @example
132
158
  * ```tsx
133
- * const { sessionUsage, sessionCost, recordTurn, resetSession } = useVibezSession();
134
- *
135
- * // Inside useChat onFinish:
136
- * onFinish: (message, { usage }) => {
137
- * recordTurn({ model: 'gpt-5.6-sol', usage });
138
- * }
159
+ * const { messages, input, handleInputChange, handleSubmit, isLoading } = useVibezChat({
160
+ * model: 'gpt-4o-mini',
161
+ * customer: 'alex@example.com',
162
+ * });
139
163
  * ```
140
164
  */
141
- declare function useVibezSession(): VibezSessionContextValue;
142
- /**
143
- * Convenient alias
144
- */
145
- declare const useVibez: typeof useVibezSession;
165
+ declare function useVibezChat(options?: UseVibezChatOptions): {
166
+ messages: VibezChatMessage[];
167
+ setMessages: React$1.Dispatch<React$1.SetStateAction<VibezChatMessage[]>>;
168
+ input: string;
169
+ setInput: React$1.Dispatch<React$1.SetStateAction<string>>;
170
+ handleInputChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
171
+ handleSubmit: (e?: React.FormEvent) => void;
172
+ isLoading: boolean;
173
+ stop: () => void;
174
+ append: (userMessage: VibezChatMessage) => Promise<void>;
175
+ };
146
176
 
147
- declare const VibezSessionWidget: React$1.FC<VibezSessionWidgetProps>;
177
+ declare const VibezSessionWidget: React__default.FC<VibezSessionWidgetProps>;
148
178
 
149
179
  /**
150
180
  * Compact inline badge for chat input bars, headers, or navbars
151
181
  */
152
- declare const VibezSessionBadge: React$1.FC<VibezSessionBadgeProps>;
182
+ declare const VibezSessionBadge: React__default.FC<VibezSessionBadgeProps>;
183
+
184
+ interface VibezBillingNotice {
185
+ status?: 'requires_payment' | 'limit_reached' | 'upgrade_required';
186
+ customerId?: string;
187
+ customerEmail?: string;
188
+ checkoutUrl?: string;
189
+ tokensUsed?: number;
190
+ costUSD?: number;
191
+ message?: string;
192
+ }
193
+ interface VibezBillingModalProps {
194
+ notice?: VibezBillingNotice | null;
195
+ isOpen?: boolean;
196
+ onClose?: () => void;
197
+ onSuccess?: () => void;
198
+ theme?: 'light' | 'dark';
199
+ testMode?: boolean;
200
+ }
201
+ /**
202
+ * Intuitive React Modal for Stripe Top-Up, Card Registration & Paywall
203
+ */
204
+ declare const VibezBillingModal: React__default.FC<VibezBillingModalProps>;
153
205
 
154
- export { type CustomStorageAdapter, type SessionPersistenceMode, type SessionState, type SessionTurnRecord, VibezSessionBadge, type VibezSessionBadgeProps, VibezSessionContext, type VibezSessionContextValue, VibezSessionProvider, type VibezSessionProviderProps, VibezSessionWidget, type VibezSessionWidgetProps, useVibez, useVibezSession };
206
+ export { type CustomStorageAdapter, type SessionPersistenceMode, type SessionState, type SessionTurnRecord, type UseVibezChatOptions, VibezBillingModal, type VibezBillingModalProps, type VibezBillingNotice, type VibezChatMessage, VibezSessionBadge, type VibezSessionBadgeProps, VibezSessionContext, type VibezSessionContextValue, VibezSessionProvider, type VibezSessionProviderProps, VibezSessionWidget, type VibezSessionWidgetProps, useVibez, useVibezChat, useVibezSession };
@@ -1,5 +1,6 @@
1
- import { T as TokenUsage, I as InferenceCost } from '../types-CSrSmsd1.js';
2
- import React$1 from 'react';
1
+ import { T as TokenUsage, I as InferenceCost } from '../types-DCuzLVyc.js';
2
+ import * as React$1 from 'react';
3
+ import React__default from 'react';
3
4
  import 'stripe';
4
5
 
5
6
  /**
@@ -122,33 +123,84 @@ interface VibezSessionBadgeProps {
122
123
  style?: React.CSSProperties;
123
124
  }
124
125
 
125
- declare const VibezSessionContext: React$1.Context<VibezSessionContextValue | null>;
126
- declare const VibezSessionProvider: React$1.FC<VibezSessionProviderProps>;
126
+ declare const VibezSessionContext: React__default.Context<VibezSessionContextValue | null>;
127
+ declare const VibezSessionProvider: React__default.FC<VibezSessionProviderProps>;
127
128
 
128
129
  /**
129
130
  * Hook to access live session usage, cost totals, and turn recorder
131
+ */
132
+ declare function useVibezSession(): VibezSessionContextValue;
133
+ declare const useVibez: typeof useVibezSession;
134
+ interface VibezChatMessage {
135
+ id: string;
136
+ role: 'user' | 'assistant' | 'system';
137
+ content: string;
138
+ annotations?: Array<{
139
+ type: string;
140
+ reasoning?: string;
141
+ [key: string]: any;
142
+ }>;
143
+ createdAt?: Date;
144
+ }
145
+ interface UseVibezChatOptions {
146
+ api?: string;
147
+ model?: string;
148
+ customer?: string;
149
+ body?: Record<string, any>;
150
+ initialMessages?: VibezChatMessage[];
151
+ onFinish?: (message: VibezChatMessage, usage: any) => void;
152
+ onError?: (error: Error) => void;
153
+ }
154
+ /**
155
+ * Declarative, 1-line Chat Streaming Hook with automatic VibezCheck session tracking.
130
156
  *
131
157
  * @example
132
158
  * ```tsx
133
- * const { sessionUsage, sessionCost, recordTurn, resetSession } = useVibezSession();
134
- *
135
- * // Inside useChat onFinish:
136
- * onFinish: (message, { usage }) => {
137
- * recordTurn({ model: 'gpt-5.6-sol', usage });
138
- * }
159
+ * const { messages, input, handleInputChange, handleSubmit, isLoading } = useVibezChat({
160
+ * model: 'gpt-4o-mini',
161
+ * customer: 'alex@example.com',
162
+ * });
139
163
  * ```
140
164
  */
141
- declare function useVibezSession(): VibezSessionContextValue;
142
- /**
143
- * Convenient alias
144
- */
145
- declare const useVibez: typeof useVibezSession;
165
+ declare function useVibezChat(options?: UseVibezChatOptions): {
166
+ messages: VibezChatMessage[];
167
+ setMessages: React$1.Dispatch<React$1.SetStateAction<VibezChatMessage[]>>;
168
+ input: string;
169
+ setInput: React$1.Dispatch<React$1.SetStateAction<string>>;
170
+ handleInputChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
171
+ handleSubmit: (e?: React.FormEvent) => void;
172
+ isLoading: boolean;
173
+ stop: () => void;
174
+ append: (userMessage: VibezChatMessage) => Promise<void>;
175
+ };
146
176
 
147
- declare const VibezSessionWidget: React$1.FC<VibezSessionWidgetProps>;
177
+ declare const VibezSessionWidget: React__default.FC<VibezSessionWidgetProps>;
148
178
 
149
179
  /**
150
180
  * Compact inline badge for chat input bars, headers, or navbars
151
181
  */
152
- declare const VibezSessionBadge: React$1.FC<VibezSessionBadgeProps>;
182
+ declare const VibezSessionBadge: React__default.FC<VibezSessionBadgeProps>;
183
+
184
+ interface VibezBillingNotice {
185
+ status?: 'requires_payment' | 'limit_reached' | 'upgrade_required';
186
+ customerId?: string;
187
+ customerEmail?: string;
188
+ checkoutUrl?: string;
189
+ tokensUsed?: number;
190
+ costUSD?: number;
191
+ message?: string;
192
+ }
193
+ interface VibezBillingModalProps {
194
+ notice?: VibezBillingNotice | null;
195
+ isOpen?: boolean;
196
+ onClose?: () => void;
197
+ onSuccess?: () => void;
198
+ theme?: 'light' | 'dark';
199
+ testMode?: boolean;
200
+ }
201
+ /**
202
+ * Intuitive React Modal for Stripe Top-Up, Card Registration & Paywall
203
+ */
204
+ declare const VibezBillingModal: React__default.FC<VibezBillingModalProps>;
153
205
 
154
- export { type CustomStorageAdapter, type SessionPersistenceMode, type SessionState, type SessionTurnRecord, VibezSessionBadge, type VibezSessionBadgeProps, VibezSessionContext, type VibezSessionContextValue, VibezSessionProvider, type VibezSessionProviderProps, VibezSessionWidget, type VibezSessionWidgetProps, useVibez, useVibezSession };
206
+ export { type CustomStorageAdapter, type SessionPersistenceMode, type SessionState, type SessionTurnRecord, type UseVibezChatOptions, VibezBillingModal, type VibezBillingModalProps, type VibezBillingNotice, type VibezChatMessage, VibezSessionBadge, type VibezSessionBadgeProps, VibezSessionContext, type VibezSessionContextValue, VibezSessionProvider, type VibezSessionProviderProps, VibezSessionWidget, type VibezSessionWidgetProps, useVibez, useVibezChat, useVibezSession };
@@ -20,11 +20,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/react/index.ts
21
21
  var react_exports = {};
22
22
  __export(react_exports, {
23
+ VibezBillingModal: () => VibezBillingModal,
23
24
  VibezSessionBadge: () => VibezSessionBadge,
24
25
  VibezSessionContext: () => VibezSessionContext,
25
26
  VibezSessionProvider: () => VibezSessionProvider,
26
27
  VibezSessionWidget: () => VibezSessionWidget,
27
28
  useVibez: () => useVibez,
29
+ useVibezChat: () => useVibezChat,
28
30
  useVibezSession: () => useVibezSession
29
31
  });
30
32
  module.exports = __toCommonJS(react_exports);
@@ -425,6 +427,193 @@ function useVibezSession() {
425
427
  return context;
426
428
  }
427
429
  var useVibez = useVibezSession;
430
+ function useVibezChat(options = {}) {
431
+ const {
432
+ api = "/api/chat",
433
+ model = "gpt-4o-mini",
434
+ customer = "anonymous",
435
+ body = {},
436
+ initialMessages = [],
437
+ onFinish,
438
+ onError
439
+ } = options;
440
+ const session = (0, import_react2.useContext)(VibezSessionContext);
441
+ const [messages, setMessages] = (0, import_react2.useState)(initialMessages);
442
+ const [input, setInput] = (0, import_react2.useState)("");
443
+ const [isLoading, setIsLoading] = (0, import_react2.useState)(false);
444
+ const abortControllerRef = (0, import_react2.useRef)(null);
445
+ const handleInputChange = (0, import_react2.useCallback)(
446
+ (e) => {
447
+ setInput(e.target.value);
448
+ },
449
+ []
450
+ );
451
+ const append = (0, import_react2.useCallback)(
452
+ async (userMessage) => {
453
+ const updatedMessages = [...messages, userMessage];
454
+ setMessages(updatedMessages);
455
+ setIsLoading(true);
456
+ const assistantId = "msg_" + Math.random().toString(36).substring(2, 9);
457
+ let assistantContent = "";
458
+ let detectedReasoning = "";
459
+ let detectedUsage = {
460
+ promptTokens: 0,
461
+ completionTokens: 0,
462
+ totalTokens: 0,
463
+ reasoningTokens: 0
464
+ };
465
+ setMessages((prev) => [
466
+ ...prev,
467
+ {
468
+ id: assistantId,
469
+ role: "assistant",
470
+ content: "",
471
+ createdAt: /* @__PURE__ */ new Date()
472
+ }
473
+ ]);
474
+ try {
475
+ abortControllerRef.current = new AbortController();
476
+ const res = await fetch(api, {
477
+ method: "POST",
478
+ headers: { "Content-Type": "application/json" },
479
+ body: JSON.stringify({
480
+ messages: updatedMessages.map((m) => ({
481
+ role: m.role,
482
+ content: m.content
483
+ })),
484
+ model,
485
+ customer,
486
+ ...body
487
+ }),
488
+ signal: abortControllerRef.current.signal
489
+ });
490
+ if (!res.ok) {
491
+ const errData = await res.json().catch(() => ({}));
492
+ throw new Error(errData.error || `HTTP error! status: ${res.status}`);
493
+ }
494
+ const reader = res.body?.getReader();
495
+ if (!reader) throw new Error("No stream body available");
496
+ const decoder = new TextDecoder();
497
+ let buffer = "";
498
+ while (true) {
499
+ const { done, value } = await reader.read();
500
+ if (done) break;
501
+ buffer += decoder.decode(value, { stream: true });
502
+ const lines = buffer.split("\n");
503
+ buffer = lines.pop() || "";
504
+ for (const line of lines) {
505
+ if (!line.trim()) continue;
506
+ if (line.startsWith("0:")) {
507
+ try {
508
+ assistantContent += JSON.parse(line.substring(2));
509
+ } catch {
510
+ assistantContent += line.substring(2).replace(/^"|"$/g, "");
511
+ }
512
+ } else if (line.startsWith("d:")) {
513
+ try {
514
+ const data = JSON.parse(line.substring(2));
515
+ if (data.usage) {
516
+ detectedUsage = {
517
+ promptTokens: data.usage.promptTokens ?? 0,
518
+ completionTokens: data.usage.completionTokens ?? 0,
519
+ totalTokens: (data.usage.promptTokens ?? 0) + (data.usage.completionTokens ?? 0),
520
+ reasoningTokens: data.usage.reasoningTokens ?? 0
521
+ };
522
+ }
523
+ } catch {
524
+ }
525
+ } else if (line.startsWith("e:") || line.startsWith("g:")) {
526
+ try {
527
+ detectedReasoning += JSON.parse(line.substring(2));
528
+ } catch {
529
+ detectedReasoning += line.substring(2);
530
+ }
531
+ } else if (!line.startsWith("f:") && !line.startsWith("2:")) {
532
+ assistantContent += line;
533
+ }
534
+ setMessages(
535
+ (prev) => prev.map(
536
+ (msg) => msg.id === assistantId ? {
537
+ ...msg,
538
+ content: assistantContent,
539
+ annotations: detectedReasoning ? [{ type: "reasoning", reasoning: detectedReasoning }] : void 0
540
+ } : msg
541
+ )
542
+ );
543
+ }
544
+ }
545
+ if (detectedUsage.promptTokens === 0 && detectedUsage.completionTokens === 0) {
546
+ const promptWords = updatedMessages.reduce(
547
+ (acc, m) => acc + m.content.split(/\s+/).length,
548
+ 0
549
+ );
550
+ const outputWords = assistantContent.split(/\s+/).length;
551
+ detectedUsage = {
552
+ promptTokens: Math.ceil(promptWords * 1.3),
553
+ completionTokens: Math.ceil(outputWords * 1.3),
554
+ totalTokens: Math.ceil((promptWords + outputWords) * 1.3),
555
+ reasoningTokens: detectedReasoning ? Math.ceil(detectedReasoning.split(/\s+/).length * 1.3) : 0
556
+ };
557
+ }
558
+ if (session) {
559
+ session.recordTurn({
560
+ model,
561
+ usage: detectedUsage
562
+ });
563
+ }
564
+ const finalMsg = {
565
+ id: assistantId,
566
+ role: "assistant",
567
+ content: assistantContent,
568
+ annotations: detectedReasoning ? [{ type: "reasoning", reasoning: detectedReasoning }] : void 0,
569
+ createdAt: /* @__PURE__ */ new Date()
570
+ };
571
+ if (onFinish) {
572
+ onFinish(finalMsg, detectedUsage);
573
+ }
574
+ } catch (err) {
575
+ if (err.name === "AbortError") return;
576
+ console.error("[useVibezChat Error]", err);
577
+ if (onError) onError(err);
578
+ } finally {
579
+ setIsLoading(false);
580
+ }
581
+ },
582
+ [api, model, customer, body, messages, session, onFinish, onError]
583
+ );
584
+ const handleSubmit = (0, import_react2.useCallback)(
585
+ (e) => {
586
+ if (e) e.preventDefault();
587
+ if (!input.trim() || isLoading) return;
588
+ const userMsg = {
589
+ id: "msg_" + Math.random().toString(36).substring(2, 9),
590
+ role: "user",
591
+ content: input.trim(),
592
+ createdAt: /* @__PURE__ */ new Date()
593
+ };
594
+ setInput("");
595
+ append(userMsg);
596
+ },
597
+ [input, isLoading, append]
598
+ );
599
+ const stop = (0, import_react2.useCallback)(() => {
600
+ if (abortControllerRef.current) {
601
+ abortControllerRef.current.abort();
602
+ setIsLoading(false);
603
+ }
604
+ }, []);
605
+ return {
606
+ messages,
607
+ setMessages,
608
+ input,
609
+ setInput,
610
+ handleInputChange,
611
+ handleSubmit,
612
+ isLoading,
613
+ stop,
614
+ append
615
+ };
616
+ }
428
617
 
429
618
  // src/react/widget.tsx
430
619
  var import_react3 = require("react");
@@ -662,13 +851,169 @@ var VibezSessionBadge = ({
662
851
  }
663
852
  );
664
853
  };
854
+
855
+ // src/react/billing-modal.tsx
856
+ var import_react4 = require("react");
857
+ var import_jsx_runtime4 = require("react/jsx-runtime");
858
+ var CreditCardIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { className: "h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: [
859
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "2", y: "5", width: "20", height: "14", rx: "2", strokeWidth: "2" }),
860
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "2", y1: "10", x2: "22", y2: "10", strokeWidth: "2" })
861
+ ] });
862
+ var ShieldCheckIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" }) });
863
+ var ZapIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polygon", { points: "13 2 3 14 12 14 11 22 21 10 12 10 13 2", strokeWidth: "2", strokeLinejoin: "round" }) });
864
+ var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: [
865
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18", strokeWidth: "2", strokeLinecap: "round" }),
866
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18", strokeWidth: "2", strokeLinecap: "round" })
867
+ ] });
868
+ var CheckIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "20 6 9 17 4 12", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) });
869
+ var ArrowRightIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: [
870
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "5", y1: "12", x2: "19", y2: "12", strokeWidth: "2", strokeLinecap: "round" }),
871
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "12 5 19 12 12 19", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })
872
+ ] });
873
+ var VibezBillingModal = ({
874
+ notice,
875
+ isOpen: explicitIsOpen,
876
+ onClose,
877
+ onSuccess,
878
+ theme = "light",
879
+ testMode = true
880
+ }) => {
881
+ const [loading, setLoading] = (0, import_react4.useState)(false);
882
+ const [successState, setSuccessState] = (0, import_react4.useState)(false);
883
+ const [selectedPlan, setSelectedPlan] = (0, import_react4.useState)("starter");
884
+ const isVisible = explicitIsOpen !== void 0 ? explicitIsOpen : Boolean(notice);
885
+ if (!isVisible) return null;
886
+ const handleSimulatePayment = async () => {
887
+ setLoading(true);
888
+ if (notice?.checkoutUrl) {
889
+ window.location.href = notice.checkoutUrl;
890
+ return;
891
+ }
892
+ await new Promise((r) => setTimeout(r, 1200));
893
+ setLoading(false);
894
+ setSuccessState(true);
895
+ setTimeout(() => {
896
+ setSuccessState(false);
897
+ if (onSuccess) onSuccess();
898
+ if (onClose) onClose();
899
+ }, 1500);
900
+ };
901
+ const isLight = theme === "light";
902
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-slate-900/60 backdrop-blur-sm animate-in fade-in duration-200", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
903
+ "div",
904
+ {
905
+ className: `relative w-full max-w-md rounded-2xl shadow-2xl border transition-all overflow-hidden ${isLight ? "bg-white border-slate-200 text-slate-900" : "bg-slate-900 border-slate-800 text-white"}`,
906
+ children: [
907
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "h-1.5 w-full bg-gradient-to-r from-indigo-500 via-purple-500 to-emerald-500" }),
908
+ onClose && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
909
+ "button",
910
+ {
911
+ onClick: onClose,
912
+ className: "absolute top-3.5 right-3.5 p-1 rounded-lg text-slate-400 hover:text-slate-700 hover:bg-slate-100 transition",
913
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CloseIcon, {})
914
+ }
915
+ ),
916
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "p-6 space-y-5", children: [
917
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-3", children: [
918
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "h-10 w-10 rounded-xl bg-indigo-600 flex items-center justify-center text-white shadow-md shadow-indigo-500/20 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CreditCardIcon, {}) }),
919
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
920
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-2", children: [
921
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { className: "font-bold text-base tracking-tight", children: notice?.status === "limit_reached" ? "Token Limit Reached" : "Add Billing Credits" }),
922
+ testMode && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-[10px] uppercase font-bold px-2 py-0.5 rounded-full bg-amber-50 text-amber-700 border border-amber-200", children: "Stripe Sandbox" })
923
+ ] }),
924
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-xs text-slate-500 mt-0.5", children: notice?.message || "Top up your account to continue streaming AI tokens." })
925
+ ] })
926
+ ] }),
927
+ (notice?.tokensUsed || notice?.costUSD) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
928
+ "div",
929
+ {
930
+ className: `p-3 rounded-xl border flex items-center justify-between text-xs ${isLight ? "bg-slate-50 border-slate-200" : "bg-slate-800 border-slate-700"}`,
931
+ children: [
932
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
933
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-slate-400", children: "Tokens Metered:" }),
934
+ " ",
935
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { className: "text-slate-800 font-semibold", children: notice.tokensUsed?.toLocaleString() || 0 })
936
+ ] }),
937
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
938
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-slate-400", children: "Cost:" }),
939
+ " ",
940
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("strong", { className: "text-indigo-600 font-semibold", children: [
941
+ "$",
942
+ notice.costUSD?.toFixed(4) || "0.0000",
943
+ " USD"
944
+ ] })
945
+ ] })
946
+ ]
947
+ }
948
+ ),
949
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "space-y-2", children: [
950
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { className: "text-xs font-semibold text-slate-500 uppercase tracking-wider", children: "Select Top-Up Option" }),
951
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "grid grid-cols-2 gap-2.5", children: [
952
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
953
+ "button",
954
+ {
955
+ type: "button",
956
+ onClick: () => setSelectedPlan("starter"),
957
+ className: `p-3 rounded-xl border text-left transition relative ${selectedPlan === "starter" ? "border-indigo-600 bg-indigo-50/60 ring-2 ring-indigo-500/20" : isLight ? "border-slate-200 bg-white hover:border-slate-300" : "border-slate-800 bg-slate-800/50"}`,
958
+ children: [
959
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "text-xs font-bold text-slate-900", children: "$5.00 Top-Up" }),
960
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "text-[11px] text-slate-500 mt-0.5", children: "500k AI Tokens" })
961
+ ]
962
+ }
963
+ ),
964
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
965
+ "button",
966
+ {
967
+ type: "button",
968
+ onClick: () => setSelectedPlan("pro"),
969
+ className: `p-3 rounded-xl border text-left transition relative ${selectedPlan === "pro" ? "border-indigo-600 bg-indigo-50/60 ring-2 ring-indigo-500/20" : isLight ? "border-slate-200 bg-white hover:border-slate-300" : "border-slate-800 bg-slate-800/50"}`,
970
+ children: [
971
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "text-xs font-bold text-slate-900", children: "$20.00 Pro" }),
972
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "text-[11px] text-slate-500 mt-0.5", children: "2.5M AI Tokens" })
973
+ ]
974
+ }
975
+ )
976
+ ] })
977
+ ] }),
978
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
979
+ "button",
980
+ {
981
+ onClick: handleSimulatePayment,
982
+ disabled: loading || successState,
983
+ className: "w-full py-2.5 px-4 rounded-xl bg-indigo-600 hover:bg-indigo-500 disabled:opacity-50 text-white text-sm font-semibold flex items-center justify-center gap-2 shadow-md shadow-indigo-500/20 transition",
984
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Processing Stripe Sandbox Checkout..." }) : successState ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "flex items-center gap-1.5 text-emerald-300 font-semibold", children: [
985
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CheckIcon, {}),
986
+ " Credits Added Successfully!"
987
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "flex items-center gap-1.5", children: [
988
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Checkout with Stripe" }),
989
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ArrowRightIcon, {})
990
+ ] })
991
+ }
992
+ ),
993
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center justify-center gap-4 text-[11px] text-slate-400 pt-1 border-t border-slate-100", children: [
994
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-1", children: [
995
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ShieldCheckIcon, {}),
996
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Stripe v2 Meter Events" })
997
+ ] }),
998
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-1", children: [
999
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ZapIcon, {}),
1000
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Zero Latency Telemetry" })
1001
+ ] })
1002
+ ] })
1003
+ ] })
1004
+ ]
1005
+ }
1006
+ ) });
1007
+ };
665
1008
  // Annotate the CommonJS export names for ESM import in node:
666
1009
  0 && (module.exports = {
1010
+ VibezBillingModal,
667
1011
  VibezSessionBadge,
668
1012
  VibezSessionContext,
669
1013
  VibezSessionProvider,
670
1014
  VibezSessionWidget,
671
1015
  useVibez,
1016
+ useVibezChat,
672
1017
  useVibezSession
673
1018
  });
674
1019
  //# sourceMappingURL=index.js.map