@lastbrain/module-ai 0.1.17 → 0.1.19
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/ai.build.config.d.ts.map +1 -1
- package/dist/ai.build.config.js +65 -1
- package/dist/api/admin/token-packs/[id].d.ts +28 -0
- package/dist/api/admin/token-packs/[id].d.ts.map +1 -0
- package/dist/api/admin/token-packs/[id].js +44 -0
- package/dist/api/admin/token-packs.d.ts +20 -0
- package/dist/api/admin/token-packs.d.ts.map +1 -0
- package/dist/api/admin/token-packs.js +57 -0
- package/dist/api/admin/user-token.js +2 -1
- package/dist/api/auth/create-checkout.d.ts +31 -0
- package/dist/api/auth/create-checkout.d.ts.map +1 -0
- package/dist/api/auth/create-checkout.js +93 -0
- package/dist/api/auth/generate-image.d.ts +3 -3
- package/dist/api/auth/generate-image.d.ts.map +1 -1
- package/dist/api/auth/generate-image.js +68 -27
- package/dist/api/auth/token-checkout.d.ts +12 -0
- package/dist/api/auth/token-checkout.d.ts.map +1 -0
- package/dist/api/auth/token-checkout.js +79 -0
- package/dist/api/auth/token-packs.d.ts +11 -0
- package/dist/api/auth/token-packs.d.ts.map +1 -0
- package/dist/api/auth/token-packs.js +29 -0
- package/dist/api/public/webhook.d.ts +2 -0
- package/dist/api/public/webhook.d.ts.map +1 -0
- package/dist/api/public/webhook.js +171 -0
- package/dist/components/DocUsageCustom.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/web/admin/AdminTokenPacksPage.d.ts +2 -0
- package/dist/web/admin/AdminTokenPacksPage.d.ts.map +1 -0
- package/dist/web/admin/AdminTokenPacksPage.js +127 -0
- package/dist/web/auth/TokenPage.d.ts.map +1 -1
- package/dist/web/auth/TokenPage.js +51 -3
- package/dist/web/components/ImageGenerative.d.ts +5 -2
- package/dist/web/components/ImageGenerative.d.ts.map +1 -1
- package/dist/web/components/ImageGenerative.js +51 -7
- package/package.json +8 -4
- package/supabase/migrations/20251201000000_token_packs.sql +73 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
/**
|
|
3
|
+
* GET /api/ai/auth/token-packs
|
|
4
|
+
* Get active token packs available for purchase
|
|
5
|
+
*/
|
|
6
|
+
export declare function GET(): Promise<NextResponse<{
|
|
7
|
+
data: any[];
|
|
8
|
+
}> | NextResponse<{
|
|
9
|
+
error: any;
|
|
10
|
+
}>>;
|
|
11
|
+
//# sourceMappingURL=token-packs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-packs.d.ts","sourceRoot":"","sources":["../../../src/api/auth/token-packs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,YAAY,EAAE,MAAM,aAAa,CAAC;AAGxD;;;GAGG;AACH,wBAAsB,GAAG;;;;IA8BxB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { getSupabaseServerClient } from "@lastbrain/core/server";
|
|
3
|
+
/**
|
|
4
|
+
* GET /api/ai/auth/token-packs
|
|
5
|
+
* Get active token packs available for purchase
|
|
6
|
+
*/
|
|
7
|
+
export async function GET() {
|
|
8
|
+
try {
|
|
9
|
+
const supabase = await getSupabaseServerClient();
|
|
10
|
+
// Verify authentication
|
|
11
|
+
const { data: { user }, } = await supabase.auth.getUser();
|
|
12
|
+
if (!user) {
|
|
13
|
+
return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
|
|
14
|
+
}
|
|
15
|
+
// Get active packs
|
|
16
|
+
const { data, error } = await supabase
|
|
17
|
+
.from("token_packs")
|
|
18
|
+
.select("*")
|
|
19
|
+
.eq("is_active", true)
|
|
20
|
+
.order("sort_order", { ascending: true });
|
|
21
|
+
if (error)
|
|
22
|
+
throw error;
|
|
23
|
+
return NextResponse.json({ data }, { status: 200 });
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
console.error("[Token Packs] GET error:", error);
|
|
27
|
+
return NextResponse.json({ error: error.message || "Erreur lors de la récupération des packs" }, { status: 500 });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../../src/api/public/webhook.ts"],"names":[],"mappings":"AAyBA,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO,qBAkN1C"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// POST /api/ai/public/webhook - Module AI Webhook Handler
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Receives webhook calls from the central payment webhook when a token purchase
|
|
5
|
+
// payment succeeds. Adds tokens to user balance.
|
|
6
|
+
// CRITICAL: This endpoint must ONLY be callable by service_role to prevent abuse.
|
|
7
|
+
import { getSupabaseServiceClient } from "@lastbrain/core/server";
|
|
8
|
+
export async function POST(request) {
|
|
9
|
+
try {
|
|
10
|
+
const supabase = await getSupabaseServiceClient();
|
|
11
|
+
const payload = (await request.json());
|
|
12
|
+
const { payment, metadata } = payload;
|
|
13
|
+
console.log("[AI Webhook] Received webhook for payment", payment.id);
|
|
14
|
+
// Verify this is a token purchase
|
|
15
|
+
if (metadata.purpose !== "token_purchase") {
|
|
16
|
+
console.log("[AI Webhook] Not a token purchase, skipping");
|
|
17
|
+
return Response.json({ received: true }, { status: 200 });
|
|
18
|
+
}
|
|
19
|
+
if (!payment?.owner_id) {
|
|
20
|
+
return Response.json({ error: "Missing owner_id" }, { status: 400 });
|
|
21
|
+
}
|
|
22
|
+
// Extract token pack info from metadata
|
|
23
|
+
const tokenPackId = metadata.token_pack_id;
|
|
24
|
+
const tokensAmount = parseInt(metadata.tokens_amount, 10);
|
|
25
|
+
if (!tokenPackId || !tokensAmount) {
|
|
26
|
+
console.error("[AI Webhook] Missing token pack metadata");
|
|
27
|
+
return Response.json({ error: "Missing token pack metadata" }, { status: 400 });
|
|
28
|
+
}
|
|
29
|
+
// Verify token pack exists
|
|
30
|
+
const { data: pack, error: packError } = await supabase
|
|
31
|
+
.from("token_packs")
|
|
32
|
+
.select("id, name, tokens")
|
|
33
|
+
.eq("id", tokenPackId)
|
|
34
|
+
.single();
|
|
35
|
+
if (packError || !pack) {
|
|
36
|
+
console.error("[AI Webhook] Token pack not found:", tokenPackId);
|
|
37
|
+
return Response.json({ error: "Token pack not found" }, { status: 404 });
|
|
38
|
+
}
|
|
39
|
+
// Idempotency: use payment.id as ledger id and upsert on conflict
|
|
40
|
+
const ledgerOwnerId = payment.user_id || payment.owner_id;
|
|
41
|
+
const meta = {
|
|
42
|
+
token_pack_id: tokenPackId,
|
|
43
|
+
token_pack_name: pack.name,
|
|
44
|
+
payment_id: payment.id,
|
|
45
|
+
provider_payment_id: payment.provider_payment_id,
|
|
46
|
+
amount_cents: payment.amount?.value_cents,
|
|
47
|
+
currency: payment.currency,
|
|
48
|
+
};
|
|
49
|
+
try {
|
|
50
|
+
const { error: upsertErr } = await supabase
|
|
51
|
+
.from("user_token_ledger")
|
|
52
|
+
.upsert({
|
|
53
|
+
id: payment.id, // ensures idempotency across duplicate webhook deliveries
|
|
54
|
+
owner_id: ledgerOwnerId,
|
|
55
|
+
type: "purchase",
|
|
56
|
+
amount: tokensAmount,
|
|
57
|
+
model: null,
|
|
58
|
+
prompt: null,
|
|
59
|
+
meta,
|
|
60
|
+
created_by: null,
|
|
61
|
+
}, { onConflict: "id", ignoreDuplicates: true });
|
|
62
|
+
if (upsertErr) {
|
|
63
|
+
// If it's a unique violation or duplicate, treat as already processed
|
|
64
|
+
console.warn("[AI Webhook] Upsert ledger warning:", upsertErr);
|
|
65
|
+
}
|
|
66
|
+
console.log(`[AI Webhook] Credited (idempotent) ${tokensAmount} tokens to user ${ledgerOwnerId} (payment ${payment.id})`);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.error("[AI Webhook] Error upserting ledger:", error);
|
|
70
|
+
return Response.json({ error: "Error adding tokens" }, { status: 500 });
|
|
71
|
+
}
|
|
72
|
+
// Create an order for this token purchase so the user can retrieve an invoice/receipt
|
|
73
|
+
try {
|
|
74
|
+
// Check if an order already exists for this payment
|
|
75
|
+
const { data: existingOrder } = await supabase
|
|
76
|
+
.from("orders")
|
|
77
|
+
.select("id")
|
|
78
|
+
.eq("payment_id", payment.id)
|
|
79
|
+
.maybeSingle();
|
|
80
|
+
if (!existingOrder) {
|
|
81
|
+
// Create order record
|
|
82
|
+
const { data: order, error: orderErr } = await supabase
|
|
83
|
+
.from("orders")
|
|
84
|
+
.insert({
|
|
85
|
+
owner_id: payment.owner_id,
|
|
86
|
+
user_id: payment.user_id,
|
|
87
|
+
cart_id: payment.cart_id || null,
|
|
88
|
+
payment_id: payment.id,
|
|
89
|
+
external_invoice_id: payload.externalInvoiceId || null,
|
|
90
|
+
payment_status: "succeeded",
|
|
91
|
+
order_status: "completed",
|
|
92
|
+
currency: payment.currency,
|
|
93
|
+
subtotal_cents: payment.amount?.value_cents || 0,
|
|
94
|
+
total_cents: payment.amount?.value_cents || 0,
|
|
95
|
+
paid_at: new Date().toISOString(),
|
|
96
|
+
})
|
|
97
|
+
.select()
|
|
98
|
+
.single();
|
|
99
|
+
if (orderErr) {
|
|
100
|
+
console.warn("[AI Webhook] Could not create order for token purchase:", orderErr);
|
|
101
|
+
}
|
|
102
|
+
else if (order?.id) {
|
|
103
|
+
// Create a single order item representing the token pack
|
|
104
|
+
const { error: itemErr } = await supabase.from("order_items").insert({
|
|
105
|
+
owner_id: payment.owner_id,
|
|
106
|
+
order_id: order.id,
|
|
107
|
+
product_id: tokenPackId,
|
|
108
|
+
variant_id: null,
|
|
109
|
+
name: pack.name,
|
|
110
|
+
sku: null,
|
|
111
|
+
unit_price_cents: payment.amount?.value_cents || 0,
|
|
112
|
+
currency: payment.currency,
|
|
113
|
+
quantity: 1,
|
|
114
|
+
total_cents: payment.amount?.value_cents || 0,
|
|
115
|
+
snapshot: { token_pack_id: tokenPackId, tokens: pack.tokens },
|
|
116
|
+
});
|
|
117
|
+
if (itemErr) {
|
|
118
|
+
console.warn("[AI Webhook] Could not insert order item:", itemErr);
|
|
119
|
+
}
|
|
120
|
+
// Link payment to order for downstream queries
|
|
121
|
+
const { error: linkErr } = await supabase
|
|
122
|
+
.from("payments")
|
|
123
|
+
.update({ order_id: order.id })
|
|
124
|
+
.eq("id", payment.id)
|
|
125
|
+
.eq("owner_id", payment.owner_id);
|
|
126
|
+
if (linkErr) {
|
|
127
|
+
console.warn("[AI Webhook] Could not link payment to order:", linkErr);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
console.log(`[AI Webhook] Created order ${order.id} for token purchase and linked payment`);
|
|
131
|
+
}
|
|
132
|
+
// Delete the dedicated token cart (and its items) after order creation
|
|
133
|
+
if (payment.cart_id) {
|
|
134
|
+
try {
|
|
135
|
+
const { error: delItemsErr } = await supabase
|
|
136
|
+
.from("cart_items")
|
|
137
|
+
.delete()
|
|
138
|
+
.eq("cart_id", payment.cart_id)
|
|
139
|
+
.eq("owner_id", payment.owner_id);
|
|
140
|
+
if (delItemsErr) {
|
|
141
|
+
console.warn("[AI Webhook] Could not delete token cart items:", delItemsErr);
|
|
142
|
+
}
|
|
143
|
+
const { error: delCartErr } = await supabase
|
|
144
|
+
.from("carts")
|
|
145
|
+
.delete()
|
|
146
|
+
.eq("id", payment.cart_id)
|
|
147
|
+
.eq("owner_id", payment.owner_id);
|
|
148
|
+
if (delCartErr) {
|
|
149
|
+
console.warn("[AI Webhook] Could not delete token cart:", delCartErr);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
console.log(`[AI Webhook] Deleted token cart ${payment.cart_id}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (cartDeleteErr) {
|
|
156
|
+
console.warn("[AI Webhook] Token cart deletion failed:", cartDeleteErr);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch (orderCreateErr) {
|
|
163
|
+
console.warn("[AI Webhook] Order creation for token purchase failed:", orderCreateErr);
|
|
164
|
+
}
|
|
165
|
+
return Response.json({ received: true, tokens_added: tokensAmount }, { status: 200 });
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
console.error("[AI Webhook] Error:", error);
|
|
169
|
+
return Response.json({ error: error instanceof Error ? error.message : "Webhook error" }, { status: 400 });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -12,7 +12,7 @@ import { Lightbulb } from "lucide-react";
|
|
|
12
12
|
* de vos composants avec des exemples interactifs.
|
|
13
13
|
*/
|
|
14
14
|
export function DocUsageCustom() {
|
|
15
|
-
return (_jsxs("div", { className: "space-y-6", children: [_jsx(Alert, { hideIcon: true, variant: "flat", color: "primary", className: "mb-6", children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(Lightbulb, { size: 20, className: "mt-0.5
|
|
15
|
+
return (_jsxs("div", { className: "space-y-6", children: [_jsx(Alert, { hideIcon: true, variant: "flat", color: "primary", className: "mb-6", children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(Lightbulb, { size: 20, className: "mt-0.5 shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold", children: "Composants IA G\u00E9n\u00E9ratives" }), _jsx("p", { className: "text-sm mt-1", children: "Le module AI fournit des composants pr\u00EAts \u00E0 l'emploi pour int\u00E9grer la g\u00E9n\u00E9ration de texte et d'images par IA dans vos applications." })] })] }) }), _jsxs(Tabs, { "aria-label": "Exemples d'utilisation", color: "primary", variant: "bordered", fullWidth: true, children: [_jsx(Tab, { title: "G\u00E9n\u00E9ration de Texte", children: _jsxs(Card, { className: "mt-4", children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-xl font-semibold", children: "TextareaGenerative" }) }), _jsxs(CardBody, { className: "space-y-6", children: [_jsxs("div", { children: [_jsx("h4", { className: "text-lg font-semibold mb-2", children: "Description" }), _jsx("p", { className: "text-slate-600 dark:text-slate-400", children: "Composant de g\u00E9n\u00E9ration de texte avec gestion automatique des tokens, support de streaming, et affichage du co\u00FBt en temps r\u00E9el." })] }), _jsxs("div", { children: [_jsx("h4", { className: "text-lg font-semibold mb-3", children: "Exemple interactif" }), _jsx(TextareaGenerative, { defaultPrompt: "\u00C9cris une courte description pour un produit innovant", placeholder: "Le texte g\u00E9n\u00E9r\u00E9 appara\u00EEtra ici...", model: "gpt-4o-mini", showTokenBalance: true })] }), _jsxs("div", { children: [_jsx("h4", { className: "text-lg font-semibold mb-2", children: "Code d'utilisation" }), _jsx(Alert, { hideIcon: true, variant: "flat", color: "primary", className: "p-4", children: _jsx("pre", { className: "whitespace-pre-wrap text-sm", children: `import { TextareaGenerative } from "@lastbrain/module-ai";
|
|
16
16
|
|
|
17
17
|
export function MyComponent() {
|
|
18
18
|
return (
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { TextareaGenerative } from "./web/components/TextareaGenerative.js";
|
|
|
2
2
|
export { ImageGenerative } from "./web/components/ImageGenerative.js";
|
|
3
3
|
export { TokenPage } from "./web/auth/TokenPage.js";
|
|
4
4
|
export { UserTokenPage } from "./web/admin/UserTokenPage.js";
|
|
5
|
+
export { AdminTokenPacksPage } from "./web/admin/AdminTokenPacksPage.js";
|
|
5
6
|
export { UserTokenTab } from "./components/admin/UserTokenTab.js";
|
|
6
7
|
export { Doc } from "./components/Doc.js";
|
|
7
8
|
export { Doc as AiModuleDoc } from "./components/Doc.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AAGtE,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGpD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AAGtE,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGpD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAGzE,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAGlE,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,GAAG,IAAI,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGzD,YAAY,EACV,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,wCAAwC,CAAC;AAEhD,YAAY,EACV,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,qCAAqC,CAAC;AAG7C,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ export { ImageGenerative } from "./web/components/ImageGenerative.js";
|
|
|
5
5
|
export { TokenPage } from "./web/auth/TokenPage.js";
|
|
6
6
|
// Pages Admin
|
|
7
7
|
export { UserTokenPage } from "./web/admin/UserTokenPage.js";
|
|
8
|
+
export { AdminTokenPacksPage } from "./web/admin/AdminTokenPacksPage.js";
|
|
8
9
|
// Admin Components - User Tabs
|
|
9
10
|
export { UserTokenTab } from "./components/admin/UserTokenTab.js";
|
|
10
11
|
// Documentation
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminTokenPacksPage.d.ts","sourceRoot":"","sources":["../../../src/web/admin/AdminTokenPacksPage.tsx"],"names":[],"mappings":"AA0CA,wBAAgB,mBAAmB,4CAyTlC"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useEffect } from "react";
|
|
4
|
+
import { Card, CardBody, Button, Input, Textarea, Switch, Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Spinner, addToast, Chip, } from "@lastbrain/ui";
|
|
5
|
+
import { Plus, Edit, Trash2 } from "lucide-react";
|
|
6
|
+
export function AdminTokenPacksPage() {
|
|
7
|
+
const [packs, setPacks] = useState([]);
|
|
8
|
+
const [loading, setLoading] = useState(true);
|
|
9
|
+
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
10
|
+
const [editingPack, setEditingPack] = useState(null);
|
|
11
|
+
const [formData, setFormData] = useState({
|
|
12
|
+
name: "",
|
|
13
|
+
description: "",
|
|
14
|
+
tokens: 100,
|
|
15
|
+
price_cents: 1000,
|
|
16
|
+
currency: "EUR",
|
|
17
|
+
stripe_price_id: "",
|
|
18
|
+
is_active: true,
|
|
19
|
+
sort_order: 0,
|
|
20
|
+
});
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
fetchPacks();
|
|
23
|
+
}, []);
|
|
24
|
+
const fetchPacks = async () => {
|
|
25
|
+
try {
|
|
26
|
+
setLoading(true);
|
|
27
|
+
const response = await fetch("/api/ai/admin/token-packs");
|
|
28
|
+
if (!response.ok)
|
|
29
|
+
throw new Error("Erreur lors du chargement");
|
|
30
|
+
const result = await response.json();
|
|
31
|
+
setPacks(result.data || []);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
addToast({ color: "danger", title: error.message });
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
setLoading(false);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const handleCreate = () => {
|
|
41
|
+
setEditingPack(null);
|
|
42
|
+
setFormData({
|
|
43
|
+
name: "",
|
|
44
|
+
description: "",
|
|
45
|
+
tokens: 100,
|
|
46
|
+
price_cents: 1000,
|
|
47
|
+
currency: "EUR",
|
|
48
|
+
stripe_price_id: "",
|
|
49
|
+
is_active: true,
|
|
50
|
+
sort_order: 0,
|
|
51
|
+
});
|
|
52
|
+
setIsModalOpen(true);
|
|
53
|
+
};
|
|
54
|
+
const handleEdit = (pack) => {
|
|
55
|
+
setEditingPack(pack);
|
|
56
|
+
setFormData({
|
|
57
|
+
name: pack.name,
|
|
58
|
+
description: pack.description || "",
|
|
59
|
+
tokens: pack.tokens,
|
|
60
|
+
price_cents: pack.price_cents,
|
|
61
|
+
currency: pack.currency,
|
|
62
|
+
stripe_price_id: pack.stripe_price_id || "",
|
|
63
|
+
is_active: pack.is_active,
|
|
64
|
+
sort_order: pack.sort_order,
|
|
65
|
+
});
|
|
66
|
+
setIsModalOpen(true);
|
|
67
|
+
};
|
|
68
|
+
const handleSave = async () => {
|
|
69
|
+
try {
|
|
70
|
+
const url = editingPack
|
|
71
|
+
? `/api/ai/admin/token-packs/${editingPack.id}`
|
|
72
|
+
: "/api/ai/admin/token-packs";
|
|
73
|
+
const method = editingPack ? "PUT" : "POST";
|
|
74
|
+
const response = await fetch(url, {
|
|
75
|
+
method,
|
|
76
|
+
headers: { "Content-Type": "application/json" },
|
|
77
|
+
body: JSON.stringify(formData),
|
|
78
|
+
});
|
|
79
|
+
if (!response.ok)
|
|
80
|
+
throw new Error("Erreur lors de la sauvegarde");
|
|
81
|
+
addToast({
|
|
82
|
+
color: "success",
|
|
83
|
+
title: editingPack ? "Pack mis à jour" : "Pack créé",
|
|
84
|
+
});
|
|
85
|
+
setIsModalOpen(false);
|
|
86
|
+
fetchPacks();
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
addToast({ color: "danger", title: error.message });
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const handleDelete = async (id) => {
|
|
93
|
+
if (!confirm("Êtes-vous sûr de vouloir supprimer ce pack ?"))
|
|
94
|
+
return;
|
|
95
|
+
try {
|
|
96
|
+
const response = await fetch(`/api/ai/admin/token-packs/${id}`, {
|
|
97
|
+
method: "DELETE",
|
|
98
|
+
});
|
|
99
|
+
if (!response.ok)
|
|
100
|
+
throw new Error("Erreur lors de la suppression");
|
|
101
|
+
addToast({ color: "success", title: "Pack supprimé" });
|
|
102
|
+
fetchPacks();
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
addToast({ color: "danger", title: error.message });
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
const formatPrice = (cents, currency) => {
|
|
109
|
+
return new Intl.NumberFormat("fr-FR", {
|
|
110
|
+
style: "currency",
|
|
111
|
+
currency,
|
|
112
|
+
}).format(cents / 100);
|
|
113
|
+
};
|
|
114
|
+
if (loading) {
|
|
115
|
+
return (_jsx("div", { className: "flex justify-center items-center min-h-96", children: _jsx(Spinner, { size: "lg" }) }));
|
|
116
|
+
}
|
|
117
|
+
return (_jsxs("div", { className: "container mx-auto p-6 max-w-7xl", children: [_jsxs("div", { className: "flex justify-between items-center mb-6", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-3xl font-bold mb-2", children: "Token Packs" }), _jsx("p", { className: "text-gray-500", children: "Gestion des packs de tokens disponibles \u00E0 l'achat" })] }), _jsx(Button, { color: "primary", onPress: handleCreate, startContent: _jsx(Plus, { size: 20 }), children: "Nouveau pack" })] }), _jsx(Card, { children: _jsx(CardBody, { children: _jsxs(Table, { "aria-label": "Token packs", children: [_jsxs(TableHeader, { children: [_jsx(TableColumn, { children: "NOM" }), _jsx(TableColumn, { children: "TOKENS" }), _jsx(TableColumn, { children: "PRIX" }), _jsx(TableColumn, { children: "STATUT" }), _jsx(TableColumn, { children: "ORDRE" }), _jsx(TableColumn, { children: "ACTIONS" })] }), _jsx(TableBody, { children: packs.map((pack) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsxs("div", { children: [_jsx("p", { className: "font-semibold", children: pack.name }), pack.description && (_jsx("p", { className: "text-sm text-gray-500", children: pack.description }))] }) }), _jsx(TableCell, { children: _jsxs(Chip, { size: "sm", variant: "flat", color: "primary", children: [pack.tokens.toLocaleString(), " tokens"] }) }), _jsx(TableCell, { children: _jsx("span", { className: "font-semibold", children: formatPrice(pack.price_cents, pack.currency) }) }), _jsx(TableCell, { children: _jsx(Chip, { size: "sm", variant: "flat", color: pack.is_active ? "success" : "default", children: pack.is_active ? "Actif" : "Inactif" }) }), _jsx(TableCell, { children: pack.sort_order }), _jsx(TableCell, { children: _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { isIconOnly: true, size: "sm", variant: "light", onPress: () => handleEdit(pack), children: _jsx(Edit, { size: 16 }) }), _jsx(Button, { isIconOnly: true, size: "sm", variant: "light", color: "danger", onPress: () => handleDelete(pack.id), children: _jsx(Trash2, { size: 16 }) })] }) })] }, pack.id))) })] }) }) }), _jsx(Modal, { isOpen: isModalOpen, onClose: () => setIsModalOpen(false), size: "2xl", children: _jsxs(ModalContent, { children: [_jsx(ModalHeader, { children: editingPack ? "Modifier le pack" : "Nouveau pack" }), _jsx(ModalBody, { children: _jsxs("div", { className: "space-y-4", children: [_jsx(Input, { label: "Nom", placeholder: "Pack Starter", value: formData.name, onChange: (e) => setFormData({ ...formData, name: e.target.value }) }), _jsx(Textarea, { label: "Description", placeholder: "Description du pack", value: formData.description, onChange: (e) => setFormData({ ...formData, description: e.target.value }) }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Nombre de tokens", type: "number", value: formData.tokens.toString(), onChange: (e) => setFormData({
|
|
118
|
+
...formData,
|
|
119
|
+
tokens: parseInt(e.target.value) || 0,
|
|
120
|
+
}) }), _jsx(Input, { label: "Prix (centimes)", type: "number", value: formData.price_cents.toString(), onChange: (e) => setFormData({
|
|
121
|
+
...formData,
|
|
122
|
+
price_cents: parseInt(e.target.value) || 0,
|
|
123
|
+
}) })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Devise", value: formData.currency, onChange: (e) => setFormData({ ...formData, currency: e.target.value }) }), _jsx(Input, { label: "Ordre d'affichage", type: "number", value: formData.sort_order.toString(), onChange: (e) => setFormData({
|
|
124
|
+
...formData,
|
|
125
|
+
sort_order: parseInt(e.target.value) || 0,
|
|
126
|
+
}) })] }), _jsx(Input, { label: "Stripe Price ID (optionnel)", placeholder: "price_...", value: formData.stripe_price_id, onChange: (e) => setFormData({ ...formData, stripe_price_id: e.target.value }) }), _jsx(Switch, { isSelected: formData.is_active, onValueChange: (checked) => setFormData({ ...formData, is_active: checked }), children: "Pack actif" })] }) }), _jsxs(ModalFooter, { children: [_jsx(Button, { variant: "light", onPress: () => setIsModalOpen(false), children: "Annuler" }), _jsx(Button, { color: "primary", onPress: handleSave, children: editingPack ? "Mettre à jour" : "Créer" })] })] }) })] }));
|
|
127
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokenPage.d.ts","sourceRoot":"","sources":["../../../src/web/auth/TokenPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TokenPage.d.ts","sourceRoot":"","sources":["../../../src/web/auth/TokenPage.tsx"],"names":[],"mappings":"AAgEA,wBAAgB,SAAS,4CAobxB"}
|
|
@@ -11,6 +11,8 @@ export function TokenPage() {
|
|
|
11
11
|
const [transactions, setTransactions] = useState([]);
|
|
12
12
|
const [selectedMonth, setSelectedMonth] = useState(new Date().toISOString().slice(0, 7));
|
|
13
13
|
const [monthlyStats, setMonthlyStats] = useState(null);
|
|
14
|
+
const [tokenPacks, setTokenPacks] = useState([]);
|
|
15
|
+
const [checkoutLoading, setCheckoutLoading] = useState(null);
|
|
14
16
|
// Générer les 12 derniers mois
|
|
15
17
|
const availableMonths = Array.from({ length: 12 }, (_, i) => {
|
|
16
18
|
const date = new Date();
|
|
@@ -57,6 +59,12 @@ export function TokenPage() {
|
|
|
57
59
|
used,
|
|
58
60
|
net: added - used,
|
|
59
61
|
});
|
|
62
|
+
// Récupérer les packs disponibles
|
|
63
|
+
const packsResponse = await fetch("/api/ai/auth/token-packs");
|
|
64
|
+
if (packsResponse.ok) {
|
|
65
|
+
const packsData = await packsResponse.json();
|
|
66
|
+
setTokenPacks(packsData.data || []);
|
|
67
|
+
}
|
|
60
68
|
}
|
|
61
69
|
catch (error) {
|
|
62
70
|
console.error("Erreur:", error);
|
|
@@ -99,16 +107,56 @@ export function TokenPage() {
|
|
|
99
107
|
};
|
|
100
108
|
return colors[type] || "default";
|
|
101
109
|
};
|
|
110
|
+
const handleBuyTokens = async (packId) => {
|
|
111
|
+
try {
|
|
112
|
+
setCheckoutLoading(packId);
|
|
113
|
+
const response = await fetch("/api/ai/auth/token-checkout", {
|
|
114
|
+
method: "POST",
|
|
115
|
+
headers: { "Content-Type": "application/json" },
|
|
116
|
+
body: JSON.stringify({ pack_id: packId }),
|
|
117
|
+
});
|
|
118
|
+
if (!response.ok) {
|
|
119
|
+
const error = await response.json();
|
|
120
|
+
throw new Error(error.error || "Erreur lors du checkout");
|
|
121
|
+
}
|
|
122
|
+
const data = await response.json();
|
|
123
|
+
if (data.checkout_url) {
|
|
124
|
+
window.location.href = data.checkout_url;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
addToast({
|
|
129
|
+
color: "danger",
|
|
130
|
+
title: error.message || "Erreur lors du checkout",
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
setCheckoutLoading(null);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
const formatPrice = (cents, currency) => {
|
|
138
|
+
return new Intl.NumberFormat("fr-FR", {
|
|
139
|
+
style: "currency",
|
|
140
|
+
currency,
|
|
141
|
+
}).format(cents / 100);
|
|
142
|
+
};
|
|
143
|
+
const formatTokensShort = (tokens) => {
|
|
144
|
+
if (tokens >= 10000) {
|
|
145
|
+
const thousands = Math.round(tokens / 1000);
|
|
146
|
+
return `${thousands}K`;
|
|
147
|
+
}
|
|
148
|
+
return tokens.toLocaleString();
|
|
149
|
+
};
|
|
102
150
|
if (!user) {
|
|
103
151
|
return (_jsx("div", { className: "flex justify-center items-center min-h-96", children: _jsxs("div", { className: "text-center", children: [_jsx(AlertCircle, { className: "mx-auto mb-4", size: 48 }), _jsx("p", { className: "text-gray-500", children: "Veuillez vous connecter" })] }) }));
|
|
104
152
|
}
|
|
105
153
|
if (loading) {
|
|
106
154
|
return (_jsx("div", { className: "flex justify-center items-center min-h-96", children: _jsx(Spinner, { size: "lg" }) }));
|
|
107
155
|
}
|
|
108
|
-
return (_jsxs("div", { className: "container mx-auto p-6 max-w-7xl", children: [_jsxs("div", { className: "mb-6", children: [_jsx("h1", { className: "text-3xl font-bold mb-2", children: "Mes Tokens IA" }), _jsx("p", { className: "text-gray-500", children: "G\u00E9rez votre solde et consultez votre historique de consommation" })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4 mb-6", children: [_jsx(Card, { children: _jsxs(CardBody, { className: "text-center py-6", children: [_jsxs("div", { className: "flex items-center justify-center gap-2 mb-2", children: [_jsx(Coins, { size: 24, className: "text-primary" }), _jsx("h3", { className: "text-sm font-medium text-gray-500", children: "Solde actuel" })] }), _jsx("p", { className: "text-4xl font-bold text-primary", children: balance?.balance
|
|
156
|
+
return (_jsxs("div", { className: "container mx-auto p-6 max-w-7xl", children: [_jsxs("div", { className: "mb-6", children: [_jsx("h1", { className: "text-3xl font-bold mb-2", children: "Mes Tokens IA" }), _jsx("p", { className: "text-gray-500", children: "G\u00E9rez votre solde et consultez votre historique de consommation" })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4 mb-6", children: [_jsx(Card, { children: _jsxs(CardBody, { className: "text-center py-6", children: [_jsxs("div", { className: "flex items-center justify-center gap-2 mb-2", children: [_jsx(Coins, { size: 24, className: "text-primary" }), _jsx("h3", { className: "text-sm font-medium text-gray-500", children: "Solde actuel" })] }), _jsx("p", { className: "text-4xl font-bold text-primary", children: formatTokensShort(balance?.balance || 0) }), _jsx("p", { className: "text-xs text-gray-400 mt-1", children: "tokens disponibles" })] }) }), _jsx(Card, { children: _jsxs(CardBody, { className: "text-center py-6", children: [_jsxs("div", { className: "flex items-center justify-center gap-2 mb-2", children: [_jsx(TrendingUp, { size: 24, className: "text-success" }), _jsx("h3", { className: "text-sm font-medium text-gray-500", children: "Total" })] }), _jsx("p", { className: "text-4xl font-bold text-success", children: formatTokensShort(balance?.totalAdded || 0) }), _jsx("p", { className: "text-xs text-gray-400 mt-1", children: "tokens achet\u00E9" })] }) }), _jsx(Card, { children: _jsxs(CardBody, { className: "text-center py-6", children: [_jsxs("div", { className: "flex items-center justify-center gap-2 mb-2", children: [_jsx(TrendingDown, { size: 24, className: "text-danger" }), _jsx("h3", { className: "text-sm font-medium text-gray-500", children: "Total utilis\u00E9" })] }), _jsx("p", { className: "text-4xl font-bold text-danger", children: formatTokensShort(balance?.totalUsed || 0) }), _jsx("p", { className: "text-xs text-gray-400 mt-1", children: "tokens consomm\u00E9s" })] }) })] }), monthlyStats && (_jsxs(Card, { className: "mb-6", children: [_jsx(CardHeader, { children: _jsxs("div", { className: "flex items-center justify-between w-full", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Calendar, { size: 20 }), _jsx("h3", { className: "text-lg font-semibold", children: "Statistiques du mois" })] }), _jsx(Select, { size: "sm", selectedKeys: [selectedMonth], onSelectionChange: (keys) => setSelectedMonth(Array.from(keys)[0]), className: "w-48", "aria-label": "S\u00E9lectionner un mois", children: availableMonths.map((month) => (_jsx(SelectItem, { textValue: month, children: new Date(month + "-01").toLocaleDateString("fr-FR", {
|
|
109
157
|
month: "long",
|
|
110
158
|
year: "numeric",
|
|
111
|
-
}) }, month))) })] }) }), _jsx(CardBody, { children: _jsxs("div", { className: "grid grid-cols-3 gap-4", children: [_jsxs("div", { className: "text-center p-4 bg-success-50 dark:bg-success-900/20 rounded-lg", children: [_jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400 mb-1", children: "Ajout\u00E9s" }), _jsxs("p", { className: "text-2xl font-bold text-success", children: ["+", monthlyStats.added
|
|
159
|
+
}) }, month))) })] }) }), _jsx(CardBody, { children: _jsxs("div", { className: "grid grid-cols-3 gap-4", children: [_jsxs("div", { className: "text-center p-4 bg-success-50 dark:bg-success-900/20 rounded-lg", children: [_jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400 mb-1", children: "Ajout\u00E9s" }), _jsxs("p", { className: "text-2xl font-bold text-success", children: ["+", formatTokensShort(monthlyStats.added)] })] }), _jsxs("div", { className: "text-center p-4 bg-danger-50 dark:bg-danger-900/20 rounded-lg", children: [_jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400 mb-1", children: "Utilis\u00E9s" }), _jsxs("p", { className: "text-2xl font-bold text-danger", children: ["-", formatTokensShort(monthlyStats.used)] })] }), _jsxs("div", { className: "text-center p-4 bg-primary-50 dark:bg-primary-900/20 rounded-lg", children: [_jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400 mb-1", children: "Solde net" }), _jsxs("p", { className: `text-2xl font-bold ${monthlyStats.net >= 0 ? "text-success" : "text-danger"}`, children: [monthlyStats.net >= 0 ? "+" : "", formatTokensShort(Math.abs(monthlyStats.net))] })] })] }) })] })), _jsxs(Card, { className: "mb-6", children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Historique des transactions" }) }), _jsx(CardBody, { children: transactions.length === 0 ? (_jsxs("div", { className: "text-center py-12 text-gray-500", children: [_jsx(Coins, { size: 48, className: "mx-auto mb-4 opacity-20" }), _jsx("p", { children: "Aucune transaction pour ce mois" })] })) : (_jsxs(Table, { "aria-label": "Historique des transactions", children: [_jsxs(TableHeader, { children: [_jsx(TableColumn, { children: "DATE" }), _jsx(TableColumn, { children: "TYPE" }), _jsx(TableColumn, { children: "DESCRIPTION" }), _jsx(TableColumn, { children: "MONTANT" }), _jsx(TableColumn, { children: "SOLDE APR\u00C8S" })] }), _jsx(TableBody, { children: transactions.map((transaction) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx("span", { className: "text-sm text-gray-600", children: formatDate(transaction.created_at) }) }), _jsx(TableCell, { children: _jsx(Chip, { size: "sm", variant: "flat", color: getTypeColor(transaction.type), children: getTypeLabel(transaction.type) }) }), _jsx(TableCell, { children: _jsx("div", { className: "max-w-md", children: _jsx("p", { className: "text-sm truncate", children: transaction.description || transaction.model || "-" }) }) }), _jsx(TableCell, { children: _jsxs("span", { className: `font-semibold ${transaction.amount > 0
|
|
112
160
|
? "text-success"
|
|
113
|
-
: "text-danger"}`, children: [transaction.amount > 0 ? "+" : "", transaction.amount
|
|
161
|
+
: "text-danger"}`, children: [transaction.amount > 0 ? "+" : "", formatTokensShort(Math.abs(transaction.amount))] }) }), _jsx(TableCell, { children: _jsx("span", { className: "text-sm text-gray-600", children: formatTokensShort(transaction.running_balance) }) })] }, transaction.id))) })] })) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(ShoppingCart, { size: 20 }), _jsx("h3", { className: "text-lg font-semibold", children: "Acheter des tokens" })] }) }), _jsx(CardBody, { children: tokenPacks.length === 0 ? (_jsxs("div", { className: "text-center py-8", children: [_jsx(ShoppingCart, { size: 48, className: "mx-auto mb-4 text-gray-300 dark:text-gray-600" }), _jsx("p", { className: "text-gray-500 mb-4", children: "Aucun pack disponible pour le moment" })] })) : (_jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4", children: tokenPacks.map((pack) => (_jsx(Card, { children: _jsxs(CardBody, { className: "text-center py-6", children: [_jsx("div", { className: "mx-auto", children: _jsx(Coins, { size: 24, className: "mx-auto mb-2 text-gray-400" }) }), _jsx("h4", { className: "text-lg font-bold mb-2", children: pack.name }), pack.description && (_jsx("p", { className: "text-sm text-gray-500 mb-4", children: pack.description })), _jsxs("div", { className: "mb-4", children: [_jsx("p", { className: "text-3xl font-bold text-primary", children: formatTokensShort(pack.tokens) }), _jsx("p", { className: "text-xs text-gray-400", children: "tokens" })] }), _jsx("p", { className: "text-xl font-semibold mb-4", children: formatPrice(pack.price_cents, pack.currency) }), _jsx(Button, { color: "primary", className: "w-full", onPress: () => handleBuyTokens(pack.id), isLoading: checkoutLoading === pack.id, startContent: checkoutLoading !== pack.id && (_jsx(ShoppingCart, { size: 16 })), children: "Acheter" })] }) }, pack.id))) })) })] })] }));
|
|
114
162
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export interface GenerativeImageResponse {
|
|
2
|
+
supabaseImageUrl?: string;
|
|
2
3
|
imageUrl: string;
|
|
3
4
|
tokensUsed: number;
|
|
4
5
|
tokensRemaining: number;
|
|
@@ -11,7 +12,7 @@ export interface ImageGenerativeProps {
|
|
|
11
12
|
model?: string;
|
|
12
13
|
size?: "256x256" | "512x512" | "1024x1024" | "1792x1024" | "1024x1792";
|
|
13
14
|
quality?: "standard" | "hd";
|
|
14
|
-
onChange?: (
|
|
15
|
+
onChange?: (supabaseImageUrl: string, response?: GenerativeImageResponse) => void;
|
|
15
16
|
onError?: (error: Error) => void;
|
|
16
17
|
className?: string;
|
|
17
18
|
disabled?: boolean;
|
|
@@ -22,6 +23,8 @@ export interface ImageGenerativeProps {
|
|
|
22
23
|
defaultStyle?: string;
|
|
23
24
|
hideStyleEditor?: boolean;
|
|
24
25
|
uploadPath?: string;
|
|
26
|
+
preview?: boolean;
|
|
27
|
+
inline?: boolean;
|
|
25
28
|
}
|
|
26
|
-
export declare function ImageGenerative({ defaultPrompt, model, size, quality, onChange, onError, className, disabled, apiEndpoint, showTokenBalance, label, description, defaultStyle, hideStyleEditor, uploadPath, }: ImageGenerativeProps): import("react/jsx-runtime").JSX.Element;
|
|
29
|
+
export declare function ImageGenerative({ defaultPrompt, model, size, quality, onChange, onError, className, disabled, apiEndpoint, showTokenBalance, label, description, defaultStyle, hideStyleEditor, uploadPath, preview, inline, }: ImageGenerativeProps): import("react/jsx-runtime").JSX.Element;
|
|
27
30
|
//# sourceMappingURL=ImageGenerative.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageGenerative.d.ts","sourceRoot":"","sources":["../../../src/web/components/ImageGenerative.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ImageGenerative.d.ts","sourceRoot":"","sources":["../../../src/web/components/ImageGenerative.tsx"],"names":[],"mappings":"AAyCA,MAAM,WAAW,uBAAuB;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAiCD,MAAM,WAAW,oBAAoB;IACnC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;IACvE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,EAAE,CACT,gBAAgB,EAAE,MAAM,EACxB,QAAQ,CAAC,EAAE,uBAAuB,KAC/B,IAAI,CAAC;IACV,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,eAAe,CAAC,EAC9B,aAAkB,EAClB,KAAkB,EAClB,IAAkB,EAClB,OAAoB,EACpB,QAAQ,EACR,OAAO,EACP,SAAS,EACT,QAAgB,EAChB,WAAsC,EACtC,gBAAuB,EACvB,KAAK,EACL,WAAW,EACX,YAA0B,EAC1B,eAAuB,EACvB,UAAU,EACV,OAAc,EACd,MAAc,GACf,EAAE,oBAAoB,2CAiiBtB"}
|