flowstack-sdk 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1205 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var wagmi = require('wagmi');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+ var reactAuth = require('@privy-io/react-auth');
7
+ var wagmi$1 = require('@privy-io/wagmi');
8
+ var reactQuery = require('@tanstack/react-query');
9
+ var chains = require('viem/chains');
10
+
11
+ // src/wallet/useWalletAuth.ts
12
+
13
+ // src/mock/fixtures.ts
14
+ ({
15
+ expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1e3).toISOString()
16
+ });
17
+ [
18
+ {
19
+ workspaceId: "ws_demo_1",
20
+ name: "Demo Workspace",
21
+ description: "A demo workspace for testing",
22
+ datasetCount: 3,
23
+ visualizationCount: 5,
24
+ modelCount: 1,
25
+ createdAt: "2024-01-15T10:00:00Z",
26
+ lastAccessed: (/* @__PURE__ */ new Date()).toISOString()
27
+ },
28
+ {
29
+ workspaceId: "ws_analytics",
30
+ name: "Analytics Project",
31
+ description: "Customer analytics and insights",
32
+ datasetCount: 7,
33
+ visualizationCount: 12,
34
+ modelCount: 2,
35
+ createdAt: "2024-02-20T14:30:00Z",
36
+ lastAccessed: new Date(Date.now() - 2 * 24 * 60 * 60 * 1e3).toISOString()
37
+ },
38
+ {
39
+ workspaceId: "ws_ml_project",
40
+ name: "ML Experiments",
41
+ description: "Machine learning model experiments",
42
+ datasetCount: 5,
43
+ visualizationCount: 8,
44
+ modelCount: 4,
45
+ createdAt: "2024-03-10T09:15:00Z",
46
+ lastAccessed: new Date(Date.now() - 7 * 24 * 60 * 60 * 1e3).toISOString()
47
+ }
48
+ ];
49
+ [
50
+ {
51
+ id: "user_mock_123",
52
+ email: "demo@example.com",
53
+ name: "Demo User",
54
+ role: "owner",
55
+ status: "active",
56
+ tenantId: "t_mock_tenant",
57
+ createdAt: "2024-01-01T10:00:00Z",
58
+ lastLoginAt: (/* @__PURE__ */ new Date()).toISOString(),
59
+ lastActivityAt: (/* @__PURE__ */ new Date()).toISOString(),
60
+ metadata: { plan: "pro", company: "Demo Inc" }
61
+ },
62
+ {
63
+ id: "user_admin_456",
64
+ email: "admin@example.com",
65
+ name: "Admin User",
66
+ role: "admin",
67
+ status: "active",
68
+ tenantId: "t_mock_tenant",
69
+ createdAt: "2024-01-15T14:30:00Z",
70
+ lastLoginAt: new Date(Date.now() - 2 * 60 * 60 * 1e3).toISOString(),
71
+ lastActivityAt: new Date(Date.now() - 30 * 60 * 1e3).toISOString()
72
+ },
73
+ {
74
+ id: "user_member_789",
75
+ email: "member@example.com",
76
+ name: "Team Member",
77
+ role: "member",
78
+ status: "active",
79
+ tenantId: "t_mock_tenant",
80
+ createdAt: "2024-02-10T09:00:00Z",
81
+ lastLoginAt: new Date(Date.now() - 24 * 60 * 60 * 1e3).toISOString(),
82
+ lastActivityAt: new Date(Date.now() - 24 * 60 * 60 * 1e3).toISOString()
83
+ },
84
+ {
85
+ id: "user_suspended_101",
86
+ email: "suspended@example.com",
87
+ name: "Suspended User",
88
+ role: "member",
89
+ status: "suspended",
90
+ tenantId: "t_mock_tenant",
91
+ createdAt: "2024-02-20T11:00:00Z",
92
+ lastLoginAt: "2024-03-01T08:00:00Z",
93
+ metadata: { suspendReason: "Policy violation" }
94
+ },
95
+ {
96
+ id: "user_pending_102",
97
+ email: "pending@example.com",
98
+ name: "New User",
99
+ role: "viewer",
100
+ status: "pending_verification",
101
+ tenantId: "t_mock_tenant",
102
+ createdAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1e3).toISOString()
103
+ }
104
+ ];
105
+ [
106
+ {
107
+ id: "act_1",
108
+ userId: "user_mock_123",
109
+ activityType: "login",
110
+ description: "Logged in from Chrome on macOS",
111
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
112
+ },
113
+ {
114
+ id: "act_2",
115
+ userId: "user_mock_123",
116
+ activityType: "query_execute",
117
+ description: 'Executed query: "Show top customers"',
118
+ timestamp: new Date(Date.now() - 30 * 60 * 1e3).toISOString(),
119
+ resourceType: "workspace",
120
+ resourceId: "ws_demo_1"
121
+ },
122
+ {
123
+ id: "act_3",
124
+ userId: "user_mock_123",
125
+ activityType: "dataset_upload",
126
+ description: "Uploaded dataset: sales_data.csv",
127
+ timestamp: new Date(Date.now() - 60 * 60 * 1e3).toISOString(),
128
+ resourceType: "dataset",
129
+ resourceId: "ds_sales"
130
+ },
131
+ {
132
+ id: "act_4",
133
+ userId: "user_mock_123",
134
+ activityType: "workspace_create",
135
+ description: "Created workspace: Analytics Project",
136
+ timestamp: new Date(Date.now() - 2 * 60 * 60 * 1e3).toISOString(),
137
+ resourceType: "workspace",
138
+ resourceId: "ws_analytics"
139
+ },
140
+ {
141
+ id: "act_5",
142
+ userId: "user_mock_123",
143
+ activityType: "logout",
144
+ description: "Logged out",
145
+ timestamp: new Date(Date.now() - 24 * 60 * 60 * 1e3).toISOString()
146
+ }
147
+ ];
148
+ var FlowstackContext = react.createContext(null);
149
+ function useFlowstackOptional() {
150
+ return react.useContext(FlowstackContext);
151
+ }
152
+
153
+ // src/wallet/useWalletAuth.ts
154
+ function useWalletAuth() {
155
+ const wagmiConfig = wagmi.useConfig();
156
+ const flowstack = useFlowstackOptional();
157
+ const [isConnected, setIsConnected] = react.useState(false);
158
+ const [isLoading, setIsLoading] = react.useState(false);
159
+ const [address, setAddress] = react.useState(null);
160
+ const [isEmbeddedWallet, setIsEmbeddedWallet] = react.useState(false);
161
+ const [authMethod, setAuthMethod] = react.useState(null);
162
+ const [error, setError] = react.useState(null);
163
+ const baseUrl = flowstack?.config?.baseUrl || "https://sage-api.flowstack.fun";
164
+ react.useEffect(() => {
165
+ if (flowstack?.credentials?.apiKey) {
166
+ try {
167
+ const parts = flowstack.credentials.apiKey.split(".");
168
+ if (parts.length < 2) return;
169
+ const payload = JSON.parse(atob(parts[1]));
170
+ if (payload.wallet_address) {
171
+ setAddress(payload.wallet_address);
172
+ setIsConnected(true);
173
+ }
174
+ } catch {
175
+ }
176
+ }
177
+ }, [flowstack?.credentials]);
178
+ const loginWithPrivy = react.useCallback(async () => {
179
+ setIsLoading(true);
180
+ setError(null);
181
+ try {
182
+ const { usePrivy } = await import('@privy-io/react-auth');
183
+ throw new Error(
184
+ "loginWithPrivy must be called from a component wrapped in WalletProvider. Use the LoginButton component instead."
185
+ );
186
+ } catch (e) {
187
+ setError(e instanceof Error ? e.message : "Privy login failed");
188
+ } finally {
189
+ setIsLoading(false);
190
+ }
191
+ }, []);
192
+ const loginWithSIWE = react.useCallback(async () => {
193
+ setIsLoading(true);
194
+ setError(null);
195
+ try {
196
+ const { getAccount, signMessage } = await import('@wagmi/core');
197
+ const account = getAccount(wagmiConfig);
198
+ if (!account.address) {
199
+ throw new Error("No wallet connected. Connect MetaMask first.");
200
+ }
201
+ const nonceResp = await fetch(`${baseUrl}/auth/wallet/nonce`);
202
+ if (!nonceResp.ok) throw new Error("Failed to get SIWE nonce");
203
+ const { nonce } = await nonceResp.json();
204
+ const domain = typeof window !== "undefined" ? window.location.host : "localhost";
205
+ const origin = typeof window !== "undefined" ? window.location.origin : "http://localhost";
206
+ const chainId = account.chainId ?? wagmiConfig.chains?.[0]?.id ?? 42161;
207
+ const siweMessage = [
208
+ `${domain} wants you to sign in with your Ethereum account:`,
209
+ account.address,
210
+ "",
211
+ "Sign in to Casino with INFER tokens",
212
+ "",
213
+ `URI: ${origin}`,
214
+ `Version: 1`,
215
+ `Chain ID: ${chainId}`,
216
+ `Nonce: ${nonce}`,
217
+ `Issued At: ${(/* @__PURE__ */ new Date()).toISOString()}`
218
+ ].join("\n");
219
+ const signature = await signMessage(wagmiConfig, { message: siweMessage });
220
+ const verifyResp = await fetch(`${baseUrl}/auth/wallet/verify`, {
221
+ method: "POST",
222
+ headers: { "Content-Type": "application/json" },
223
+ body: JSON.stringify({ message: siweMessage, signature })
224
+ });
225
+ if (!verifyResp.ok) {
226
+ const err = await verifyResp.json();
227
+ throw new Error(err.detail || "SIWE verification failed");
228
+ }
229
+ const data = await verifyResp.json();
230
+ if (flowstack?.setCredentials) {
231
+ flowstack.setCredentials({
232
+ apiKey: data.session_token,
233
+ tenantId: data.tenant_id,
234
+ userId: data.user_id,
235
+ expiresAt: data.expires_at
236
+ });
237
+ }
238
+ setAddress(data.wallet_address);
239
+ setIsConnected(true);
240
+ setIsEmbeddedWallet(false);
241
+ setAuthMethod("siwe");
242
+ } catch (e) {
243
+ setError(e instanceof Error ? e.message : "SIWE login failed");
244
+ } finally {
245
+ setIsLoading(false);
246
+ }
247
+ }, [baseUrl, flowstack]);
248
+ const login = react.useCallback(async (method = "privy") => {
249
+ if (method === "privy") {
250
+ await loginWithPrivy();
251
+ } else {
252
+ await loginWithSIWE();
253
+ }
254
+ }, [loginWithPrivy, loginWithSIWE]);
255
+ const logout = react.useCallback(() => {
256
+ setIsConnected(false);
257
+ setAddress(null);
258
+ setAuthMethod(null);
259
+ setIsEmbeddedWallet(false);
260
+ setError(null);
261
+ flowstack?.logout?.();
262
+ }, [flowstack]);
263
+ return {
264
+ isConnected,
265
+ isLoading,
266
+ address,
267
+ isEmbeddedWallet,
268
+ authMethod,
269
+ error,
270
+ login,
271
+ logout
272
+ };
273
+ }
274
+ var POLL_INTERVAL_MS = 15e3;
275
+ function useInferBalance() {
276
+ const flowstack = useFlowstackOptional();
277
+ const [data, setData] = react.useState(null);
278
+ const [isLoading, setIsLoading] = react.useState(false);
279
+ const [error, setError] = react.useState(null);
280
+ const intervalRef = react.useRef(null);
281
+ const baseUrl = flowstack?.config?.baseUrl || "https://sage-api.flowstack.fun";
282
+ const apiKey = flowstack?.credentials?.apiKey;
283
+ const tenantId = flowstack?.credentials?.tenantId;
284
+ const fetchBalance = react.useCallback(async () => {
285
+ if (!apiKey) return;
286
+ setIsLoading(true);
287
+ setError(null);
288
+ try {
289
+ const resp = await fetch(`${baseUrl}/billing/infer/balance`, {
290
+ headers: {
291
+ "Authorization": `Bearer ${apiKey}`,
292
+ "X-Tenant-ID": tenantId || ""
293
+ }
294
+ });
295
+ if (resp.status === 400) {
296
+ setData(null);
297
+ return;
298
+ }
299
+ if (!resp.ok) {
300
+ throw new Error(`Balance check failed: ${resp.status}`);
301
+ }
302
+ const json = await resp.json();
303
+ setData({
304
+ balanceWei: json.balance_wei,
305
+ heldWei: json.held_wei,
306
+ availableWei: json.available_wei,
307
+ balance: json.infer_balance,
308
+ available: json.infer_available,
309
+ queryCredits: json.query_credits
310
+ });
311
+ } catch (e) {
312
+ setError(e instanceof Error ? e.message : "Failed to fetch balance");
313
+ } finally {
314
+ setIsLoading(false);
315
+ }
316
+ }, [apiKey, baseUrl, tenantId]);
317
+ react.useEffect(() => {
318
+ fetchBalance();
319
+ intervalRef.current = setInterval(fetchBalance, POLL_INTERVAL_MS);
320
+ return () => {
321
+ if (intervalRef.current) clearInterval(intervalRef.current);
322
+ };
323
+ }, [fetchBalance]);
324
+ return { data, isLoading, error, refetch: fetchBalance };
325
+ }
326
+ var POLL_INTERVAL_MS2 = 15e3;
327
+ function useAgentBalance() {
328
+ const flowstack = useFlowstackOptional();
329
+ const [data, setData] = react.useState(null);
330
+ const [isLoading, setIsLoading] = react.useState(false);
331
+ const [error, setError] = react.useState(null);
332
+ const intervalRef = react.useRef(null);
333
+ const baseUrl = flowstack?.config?.baseUrl || "https://sage-api.flowstack.fun";
334
+ const apiKey = flowstack?.credentials?.apiKey;
335
+ const tenantId = flowstack?.credentials?.tenantId;
336
+ const fetchBalance = react.useCallback(async () => {
337
+ if (!apiKey) return;
338
+ setIsLoading(true);
339
+ setError(null);
340
+ try {
341
+ const resp = await fetch(`${baseUrl}/billing/agent/balance`, {
342
+ headers: {
343
+ "Authorization": `Bearer ${apiKey}`,
344
+ "X-Tenant-ID": tenantId || ""
345
+ }
346
+ });
347
+ if (resp.status === 400) {
348
+ setData(null);
349
+ return;
350
+ }
351
+ if (!resp.ok) {
352
+ throw new Error(`AGENT balance check failed: ${resp.status}`);
353
+ }
354
+ const json = await resp.json();
355
+ setData({
356
+ balanceWei: json.balance_wei,
357
+ heldWei: json.held_wei,
358
+ availableWei: json.available_wei,
359
+ balance: json.agent_balance,
360
+ available: json.agent_available,
361
+ buildCredits: json.build_credits
362
+ });
363
+ } catch (e) {
364
+ setError(e instanceof Error ? e.message : "Failed to fetch AGENT balance");
365
+ } finally {
366
+ setIsLoading(false);
367
+ }
368
+ }, [apiKey, baseUrl, tenantId]);
369
+ react.useEffect(() => {
370
+ fetchBalance();
371
+ intervalRef.current = setInterval(fetchBalance, POLL_INTERVAL_MS2);
372
+ return () => {
373
+ if (intervalRef.current) clearInterval(intervalRef.current);
374
+ };
375
+ }, [fetchBalance]);
376
+ return { data, isLoading, error, refetch: fetchBalance };
377
+ }
378
+ var CONTRACTS = {
379
+ "arbitrum-sepolia": {
380
+ payment: "0x879101330bcB251CBB775559419cB6389346ee8c",
381
+ token: "0xD31f5765F92D7D3fF0463eeaa14C157d423aF9E1"
382
+ },
383
+ "arbitrum": {
384
+ payment: "0x879101330bcB251CBB775559419cB6389346ee8c",
385
+ token: "0xD31f5765F92D7D3fF0463eeaa14C157d423aF9E1"
386
+ }
387
+ };
388
+ var ERC20_APPROVE_ABI = [
389
+ {
390
+ name: "approve",
391
+ type: "function",
392
+ inputs: [
393
+ { name: "spender", type: "address" },
394
+ { name: "amount", type: "uint256" }
395
+ ],
396
+ outputs: [{ name: "", type: "bool" }],
397
+ stateMutability: "nonpayable"
398
+ }
399
+ ];
400
+ var DEPOSIT_ABI = [
401
+ {
402
+ name: "deposit",
403
+ type: "function",
404
+ inputs: [{ name: "amount", type: "uint256" }],
405
+ outputs: [],
406
+ stateMutability: "nonpayable"
407
+ }
408
+ ];
409
+ function useDeposit(chain = "arbitrum-sepolia") {
410
+ const wagmiConfig = wagmi.useConfig();
411
+ const [isDepositing, setIsDepositing] = react.useState(false);
412
+ const [txHash, setTxHash] = react.useState(null);
413
+ const [error, setError] = react.useState(null);
414
+ const contracts = CONTRACTS[chain] || CONTRACTS["arbitrum-sepolia"];
415
+ const deposit = react.useCallback(async (inferAmount) => {
416
+ setIsDepositing(true);
417
+ setError(null);
418
+ setTxHash(null);
419
+ try {
420
+ const { writeContract, waitForTransactionReceipt } = await import('@wagmi/core');
421
+ const { parseUnits } = await import('viem');
422
+ const amountWei = parseUnits(inferAmount.toString(), 18);
423
+ const approveTx = await writeContract(wagmiConfig, {
424
+ address: contracts.token,
425
+ abi: ERC20_APPROVE_ABI,
426
+ functionName: "approve",
427
+ args: [contracts.payment, amountWei]
428
+ });
429
+ await waitForTransactionReceipt(wagmiConfig, { hash: approveTx });
430
+ const depositTx = await writeContract(wagmiConfig, {
431
+ address: contracts.payment,
432
+ abi: DEPOSIT_ABI,
433
+ functionName: "deposit",
434
+ args: [amountWei]
435
+ });
436
+ await waitForTransactionReceipt(wagmiConfig, { hash: depositTx });
437
+ setTxHash(depositTx);
438
+ return depositTx;
439
+ } catch (e) {
440
+ const msg = e instanceof Error ? e.message : "Deposit failed";
441
+ setError(msg);
442
+ return null;
443
+ } finally {
444
+ setIsDepositing(false);
445
+ }
446
+ }, [contracts]);
447
+ return { deposit, isDepositing, txHash, error };
448
+ }
449
+ function useBuyInfer(options = {}) {
450
+ const [isBuying, setIsBuying] = react.useState(false);
451
+ const [status, setStatus] = react.useState("idle");
452
+ const [error, setError] = react.useState(null);
453
+ const buy = react.useCallback((amount) => {
454
+ if (!options.apiKey) {
455
+ setError("On-ramp not configured. Set onRampConfig in FlowstackConfig.");
456
+ return;
457
+ }
458
+ if (!options.walletAddress) {
459
+ setError("No wallet address. Sign up first.");
460
+ return;
461
+ }
462
+ setIsBuying(true);
463
+ setStatus("pending");
464
+ setError(null);
465
+ const baseUrl = options.environment === "production" ? "https://buy.moonpay.com" : "https://buy-sandbox.moonpay.com";
466
+ const params = new URLSearchParams({
467
+ apiKey: options.apiKey,
468
+ currencyCode: "infer_arbitrum",
469
+ // MoonPay currency code for INFER on Arbitrum
470
+ walletAddress: options.walletAddress,
471
+ ...amount ? { baseCurrencyAmount: amount.toString() } : {},
472
+ colorCode: "#d4a843",
473
+ // Casino amber
474
+ showWalletAddressForm: "false"
475
+ });
476
+ const widgetUrl = `${baseUrl}?${params.toString()}`;
477
+ const popup = window.open(
478
+ widgetUrl,
479
+ "moonpay",
480
+ "width=500,height=700,left=200,top=100"
481
+ );
482
+ if (!popup) {
483
+ window.location.href = widgetUrl;
484
+ return;
485
+ }
486
+ const pollInterval = setInterval(() => {
487
+ if (popup.closed) {
488
+ clearInterval(pollInterval);
489
+ setIsBuying(false);
490
+ setStatus("completed");
491
+ }
492
+ }, 1e3);
493
+ }, [options]);
494
+ return { buy, isBuying, status, error };
495
+ }
496
+ var POLL_INTERVAL_MS3 = 6e4;
497
+ function useAppAccess(siteId, opts) {
498
+ const flowstack = useFlowstackOptional();
499
+ const [hasAccess, setHasAccess] = react.useState(true);
500
+ const [queriesUsed, setQueriesUsed] = react.useState(0);
501
+ const [queriesRemaining, setQueriesRemaining] = react.useState(null);
502
+ const [paymentMode, setPaymentMode] = react.useState(null);
503
+ const [unlockPriceCents, setUnlockPriceCents] = react.useState(null);
504
+ const [unlockPriceLabel, setUnlockPriceLabel] = react.useState(null);
505
+ const [isLoading, setIsLoading] = react.useState(false);
506
+ const [error, setError] = react.useState(null);
507
+ const intervalRef = react.useRef(null);
508
+ const baseUrl = flowstack?.config?.baseUrl || "https://sage-api.flowstack.fun";
509
+ const apiKey = flowstack?.credentials?.apiKey;
510
+ const fetchStatus = react.useCallback(async () => {
511
+ if (!siteId || !apiKey) return;
512
+ setIsLoading(true);
513
+ setError(null);
514
+ try {
515
+ const params = new URLSearchParams({ site_id: siteId });
516
+ if (opts?.builderTenantId) params.set("builder_tenant_id", opts.builderTenantId);
517
+ const resp = await fetch(`${baseUrl}/billing/app-access/status?${params}`, {
518
+ headers: { Authorization: `Bearer ${apiKey}` }
519
+ });
520
+ if (!resp.ok) {
521
+ setHasAccess(true);
522
+ return;
523
+ }
524
+ const data = await resp.json();
525
+ setHasAccess(data.has_access ?? true);
526
+ setQueriesUsed(data.queries_used ?? 0);
527
+ setQueriesRemaining(data.queries_remaining ?? null);
528
+ setPaymentMode(data.payment_mode ?? null);
529
+ setUnlockPriceCents(data.unlock_price_cents ?? null);
530
+ setUnlockPriceLabel(data.unlock_price_label ?? null);
531
+ } catch (err) {
532
+ setError(err.message || "Failed to check access status");
533
+ setHasAccess(true);
534
+ } finally {
535
+ setIsLoading(false);
536
+ }
537
+ }, [siteId, apiKey, baseUrl, opts?.builderTenantId]);
538
+ react.useEffect(() => {
539
+ if (!siteId || !apiKey) return;
540
+ fetchStatus();
541
+ intervalRef.current = setInterval(fetchStatus, POLL_INTERVAL_MS3);
542
+ return () => {
543
+ if (intervalRef.current) clearInterval(intervalRef.current);
544
+ };
545
+ }, [fetchStatus, siteId, apiKey]);
546
+ const checkout = react.useCallback(
547
+ async (checkoutOpts) => {
548
+ if (!apiKey || !siteId) return;
549
+ try {
550
+ const successUrl = checkoutOpts?.successUrl || (typeof window !== "undefined" ? window.location.href : "");
551
+ const cancelUrl = checkoutOpts?.cancelUrl || (typeof window !== "undefined" ? window.location.href : "");
552
+ const resp = await fetch(`${baseUrl}/billing/app-access/checkout`, {
553
+ method: "POST",
554
+ headers: {
555
+ Authorization: `Bearer ${apiKey}`,
556
+ "Content-Type": "application/json"
557
+ },
558
+ body: JSON.stringify({
559
+ site_id: siteId,
560
+ success_url: successUrl,
561
+ cancel_url: cancelUrl
562
+ })
563
+ });
564
+ if (!resp.ok) {
565
+ const body = await resp.json().catch(() => ({}));
566
+ throw new Error(body.detail || `Checkout failed: ${resp.status}`);
567
+ }
568
+ const data = await resp.json();
569
+ if (data.url && typeof window !== "undefined") {
570
+ window.location.href = data.url;
571
+ }
572
+ } catch (err) {
573
+ setError(err.message || "Checkout failed");
574
+ }
575
+ },
576
+ [apiKey, siteId, baseUrl]
577
+ );
578
+ return {
579
+ hasAccess,
580
+ queriesUsed,
581
+ queriesRemaining,
582
+ paymentMode,
583
+ unlockPriceCents,
584
+ unlockPriceLabel,
585
+ isLoading,
586
+ error,
587
+ checkout,
588
+ refetch: fetchStatus
589
+ };
590
+ }
591
+ var WalletCtx = react.createContext({
592
+ privyReady: false,
593
+ baseUrl: "https://sage-api.flowstack.fun"
594
+ });
595
+ function WalletProvider({
596
+ children,
597
+ privyAppId,
598
+ chain = "arbitrum",
599
+ baseUrl = "https://sage-api.flowstack.fun",
600
+ walletConnectProjectId
601
+ }) {
602
+ const [queryClient] = react.useState(() => new reactQuery.QueryClient());
603
+ const selectedChain = chain === "arbitrum-sepolia" ? chains.arbitrumSepolia : chains.arbitrum;
604
+ const wagmiConfig = react.useMemo(() => {
605
+ const config = wagmi$1.createConfig({
606
+ chains: [selectedChain],
607
+ transports: { [selectedChain.id]: wagmi.http() },
608
+ // Explicit connectors so wagmi always has something to work with.
609
+ // Without these, useConnect().connectors is empty → connectAsync({ connector: undefined })
610
+ // → "undefined is not an object (evaluating 'n.uid')" crash.
611
+ connectors: [
612
+ wagmi.injected()
613
+ // MetaMask, Rabby, Brave, any browser extension wallet
614
+ ]
615
+ });
616
+ if (typeof window !== "undefined") {
617
+ window.__wagmiConfig = config;
618
+ }
619
+ return config;
620
+ }, [selectedChain]);
621
+ if (!privyAppId) {
622
+ return /* @__PURE__ */ jsxRuntime.jsx(WalletCtx.Provider, { value: { privyReady: false, baseUrl }, children: /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClient, children }) });
623
+ }
624
+ return /* @__PURE__ */ jsxRuntime.jsx(
625
+ reactAuth.PrivyProvider,
626
+ {
627
+ appId: privyAppId,
628
+ config: {
629
+ // Embedded signer — the EOA keypair that controls the smart wallet.
630
+ // Must be created for all users so the smart wallet has a signer.
631
+ // NOTE: @privy-io/react-auth v3 nests createOnLogin per chain
632
+ // (embeddedWallets.ethereum.createOnLogin). The old v2 flat shape
633
+ // (embeddedWallets.createOnLogin) is silently ignored on v3, so NO
634
+ // wallet gets created on login — the user authenticates but has no
635
+ // wallet/address. Use the v3 shape.
636
+ embeddedWallets: {
637
+ ethereum: {
638
+ createOnLogin: "all-users"
639
+ },
640
+ showWalletUIs: false
641
+ },
642
+ // EVM smart wallet (ERC-4337) — Kernel/ZeroDev implementation.
643
+ // Must be enabled in the Privy dashboard (Smart wallets → Kernel → Arbitrum).
644
+ // The smart wallet address is what Privy returns as type='smart_wallet'
645
+ // in linked_accounts, and is the canonical address for the token economy.
646
+ // @ts-ignore — 'smart_wallets' may not be in older @privy-io/react-auth types
647
+ smart_wallets: {
648
+ type: "kernel"
649
+ },
650
+ loginMethods: ["email", "google", "apple", "twitter", "github", "linkedin", "spotify", "wallet"],
651
+ appearance: { theme: "dark" },
652
+ defaultChain: selectedChain,
653
+ ...walletConnectProjectId ? { walletConnectCloudProjectId: walletConnectProjectId } : {}
654
+ },
655
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsxRuntime.jsx(wagmi$1.WagmiProvider, { config: wagmiConfig, children: /* @__PURE__ */ jsxRuntime.jsx(WalletCtx.Provider, { value: { privyReady: true, baseUrl }, children }) }) })
656
+ }
657
+ );
658
+ }
659
+ function LoginButton({
660
+ onSuccess,
661
+ onError,
662
+ showWalletOption = true,
663
+ className
664
+ }) {
665
+ const [mode, setMode] = react.useState("signup");
666
+ const [isLoading, setIsLoading] = react.useState(false);
667
+ const handlePrivyLogin = react.useCallback(async () => {
668
+ setIsLoading(true);
669
+ try {
670
+ const { usePrivy } = await import('@privy-io/react-auth');
671
+ onError?.("Use this component inside WalletProvider");
672
+ } catch (e) {
673
+ onError?.(e instanceof Error ? e.message : "Login failed");
674
+ } finally {
675
+ setIsLoading(false);
676
+ }
677
+ }, [onSuccess, onError]);
678
+ const handleWalletConnect = react.useCallback(async () => {
679
+ setIsLoading(true);
680
+ try {
681
+ onError?.("Wallet connect requires WalletProvider context");
682
+ } catch (e) {
683
+ onError?.(e instanceof Error ? e.message : "Wallet connect failed");
684
+ } finally {
685
+ setIsLoading(false);
686
+ }
687
+ }, [onError]);
688
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
689
+ mode === "signup" ? /* @__PURE__ */ jsxRuntime.jsx(
690
+ "button",
691
+ {
692
+ onClick: handlePrivyLogin,
693
+ disabled: isLoading,
694
+ style: {
695
+ padding: "12px 24px",
696
+ borderRadius: "8px",
697
+ border: "none",
698
+ backgroundColor: "#d4a843",
699
+ color: "#0a0a0a",
700
+ fontWeight: 600,
701
+ cursor: isLoading ? "not-allowed" : "pointer",
702
+ opacity: isLoading ? 0.7 : 1,
703
+ width: "100%"
704
+ },
705
+ children: isLoading ? "Signing in..." : "Sign up with Google"
706
+ }
707
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
708
+ "button",
709
+ {
710
+ onClick: handleWalletConnect,
711
+ disabled: isLoading,
712
+ style: {
713
+ padding: "12px 24px",
714
+ borderRadius: "8px",
715
+ border: "1px solid #c4bdb3",
716
+ backgroundColor: "transparent",
717
+ color: "#c4bdb3",
718
+ fontWeight: 600,
719
+ cursor: isLoading ? "not-allowed" : "pointer",
720
+ opacity: isLoading ? 0.7 : 1,
721
+ width: "100%"
722
+ },
723
+ children: isLoading ? "Connecting..." : "Connect Wallet"
724
+ }
725
+ ),
726
+ showWalletOption && /* @__PURE__ */ jsxRuntime.jsx(
727
+ "button",
728
+ {
729
+ onClick: () => setMode(mode === "signup" ? "wallet" : "signup"),
730
+ style: {
731
+ marginTop: "8px",
732
+ padding: "8px",
733
+ background: "none",
734
+ border: "none",
735
+ color: "#c4bdb3",
736
+ fontSize: "13px",
737
+ cursor: "pointer",
738
+ width: "100%",
739
+ textAlign: "center"
740
+ },
741
+ children: mode === "signup" ? "Already have INFER? Connect wallet" : "Sign up with email instead"
742
+ }
743
+ )
744
+ ] });
745
+ }
746
+ function InferBalanceBadge({
747
+ lowBalanceThreshold = 5,
748
+ onBuyMore,
749
+ className
750
+ }) {
751
+ const { data, isLoading } = useInferBalance();
752
+ if (isLoading && !data) {
753
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className, style: { ...badgeStyle, opacity: 0.5 }, children: "..." });
754
+ }
755
+ if (!data) return null;
756
+ const isLow = data.queryCredits <= lowBalanceThreshold;
757
+ return /* @__PURE__ */ jsxRuntime.jsxs(
758
+ "span",
759
+ {
760
+ className,
761
+ style: {
762
+ ...badgeStyle,
763
+ backgroundColor: isLow ? "#3a1c1c" : "#1a1a1a",
764
+ borderColor: isLow ? "#d44343" : "#333"
765
+ },
766
+ children: [
767
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: isLow ? "#d44343" : "#d4a843", fontWeight: 600 }, children: data.queryCredits }),
768
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#c4bdb3", marginLeft: "4px", fontSize: "12px" }, children: "queries" }),
769
+ isLow && onBuyMore && /* @__PURE__ */ jsxRuntime.jsx(
770
+ "button",
771
+ {
772
+ onClick: onBuyMore,
773
+ style: {
774
+ marginLeft: "8px",
775
+ padding: "2px 8px",
776
+ borderRadius: "4px",
777
+ border: "1px solid #d4a843",
778
+ backgroundColor: "transparent",
779
+ color: "#d4a843",
780
+ fontSize: "11px",
781
+ cursor: "pointer"
782
+ },
783
+ children: "Buy More"
784
+ }
785
+ )
786
+ ]
787
+ }
788
+ );
789
+ }
790
+ var badgeStyle = {
791
+ display: "inline-flex",
792
+ alignItems: "center",
793
+ padding: "4px 12px",
794
+ borderRadius: "20px",
795
+ border: "1px solid #333",
796
+ fontSize: "13px",
797
+ fontFamily: "var(--font-body, Inter, sans-serif)"
798
+ };
799
+ function AgentBalanceBadge({
800
+ lowBalanceThreshold = 2,
801
+ onBuyMore,
802
+ className
803
+ }) {
804
+ const { data, isLoading } = useAgentBalance();
805
+ if (isLoading && !data) {
806
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className, style: { ...badgeStyle2, opacity: 0.5 }, children: "..." });
807
+ }
808
+ if (!data) return null;
809
+ const isLow = data.buildCredits <= lowBalanceThreshold;
810
+ return /* @__PURE__ */ jsxRuntime.jsxs(
811
+ "span",
812
+ {
813
+ className,
814
+ style: {
815
+ ...badgeStyle2,
816
+ backgroundColor: isLow ? "#3a1c1c" : "#1a1a1a",
817
+ borderColor: isLow ? "#d44343" : "#333"
818
+ },
819
+ children: [
820
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: isLow ? "#d44343" : "#43d4a8", fontWeight: 600 }, children: data.buildCredits }),
821
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#c4bdb3", marginLeft: "4px", fontSize: "12px" }, children: "builds" }),
822
+ isLow && onBuyMore && /* @__PURE__ */ jsxRuntime.jsx(
823
+ "button",
824
+ {
825
+ onClick: onBuyMore,
826
+ style: {
827
+ marginLeft: "8px",
828
+ padding: "2px 8px",
829
+ borderRadius: "4px",
830
+ border: "1px solid #43d4a8",
831
+ backgroundColor: "transparent",
832
+ color: "#43d4a8",
833
+ fontSize: "11px",
834
+ cursor: "pointer"
835
+ },
836
+ children: "Buy More"
837
+ }
838
+ )
839
+ ]
840
+ }
841
+ );
842
+ }
843
+ var badgeStyle2 = {
844
+ display: "inline-flex",
845
+ alignItems: "center",
846
+ padding: "4px 12px",
847
+ borderRadius: "20px",
848
+ border: "1px solid #333",
849
+ fontSize: "13px",
850
+ fontFamily: "var(--font-body, Inter, sans-serif)"
851
+ };
852
+ var DEFAULT_OIF_BASE = "https://openinferencefoundation.org";
853
+ function NeedsAgent({
854
+ amountNeeded,
855
+ onProceed,
856
+ returnUrl,
857
+ children,
858
+ oifBaseUrl = DEFAULT_OIF_BASE
859
+ }) {
860
+ const { data, isLoading } = useAgentBalance();
861
+ const available = data?.available ?? 0;
862
+ const hasSufficient = available >= amountNeeded;
863
+ const handleGetAgent = () => {
864
+ const base = oifBaseUrl.replace(/\/$/, "");
865
+ const returnTo = returnUrl ?? (typeof window !== "undefined" ? window.location.href : "");
866
+ const url = `${base}/buy?returnTo=${encodeURIComponent(returnTo)}&need=${amountNeeded}`;
867
+ if (typeof window !== "undefined") {
868
+ window.open(url, "_blank", "noopener,noreferrer");
869
+ }
870
+ };
871
+ if (isLoading) {
872
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { opacity: 0.6, pointerEvents: "none" }, children });
873
+ }
874
+ if (hasSufficient) {
875
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { onClick: onProceed, style: { cursor: "pointer" }, children });
876
+ }
877
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
878
+ children && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { opacity: 0.5, pointerEvents: "none" }, children }),
879
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "flex-start", gap: 6 }, children: [
880
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { style: { margin: 0, fontSize: "0.85em", color: "#888" }, children: [
881
+ "You need ",
882
+ amountNeeded,
883
+ " AGENT to use this feature.",
884
+ data !== null && ` You have ${available.toFixed(2)}.`
885
+ ] }),
886
+ /* @__PURE__ */ jsxRuntime.jsx(
887
+ "button",
888
+ {
889
+ onClick: handleGetAgent,
890
+ style: {
891
+ background: "#6366f1",
892
+ color: "#fff",
893
+ border: "none",
894
+ borderRadius: 6,
895
+ padding: "6px 14px",
896
+ fontSize: "0.875em",
897
+ fontWeight: 600,
898
+ cursor: "pointer"
899
+ },
900
+ children: "Get AGENT \u2192"
901
+ }
902
+ )
903
+ ] })
904
+ ] });
905
+ }
906
+ function PaymentRequired({
907
+ queryCredits = 0,
908
+ inferPerQuery = 50,
909
+ onBuy,
910
+ onDismiss,
911
+ className
912
+ }) {
913
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: containerStyle, children: [
914
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "24px", marginBottom: "8px" }, children: "0 queries remaining" }),
915
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { style: { color: "#c4bdb3", marginBottom: "16px", lineHeight: 1.5 }, children: [
916
+ "Each query costs ",
917
+ inferPerQuery,
918
+ " INFER. Buy more to continue using Casino."
919
+ ] }),
920
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: onBuy, style: buyButtonStyle, children: "Buy INFER" }),
921
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "#666", fontSize: "12px", marginTop: "12px" }, children: "Pay with credit card. No crypto knowledge needed." }),
922
+ onDismiss && /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: onDismiss, style: dismissStyle, children: "Maybe later" })
923
+ ] });
924
+ }
925
+ var containerStyle = {
926
+ textAlign: "center",
927
+ padding: "32px 24px",
928
+ backgroundColor: "#111111",
929
+ borderRadius: "12px",
930
+ border: "1px solid #333",
931
+ maxWidth: "400px",
932
+ margin: "0 auto",
933
+ fontFamily: "var(--font-body, Inter, sans-serif)",
934
+ color: "#f5f0e8"
935
+ };
936
+ var buyButtonStyle = {
937
+ padding: "14px 32px",
938
+ borderRadius: "8px",
939
+ border: "none",
940
+ backgroundColor: "#d4a843",
941
+ color: "#0a0a0a",
942
+ fontWeight: 700,
943
+ fontSize: "16px",
944
+ cursor: "pointer",
945
+ width: "100%"
946
+ };
947
+ var dismissStyle = {
948
+ marginTop: "8px",
949
+ padding: "8px",
950
+ background: "none",
951
+ border: "none",
952
+ color: "#666",
953
+ fontSize: "13px",
954
+ cursor: "pointer"
955
+ };
956
+ var TIERS = [
957
+ { queries: 100, infer: 5e3, price: 5 },
958
+ { queries: 500, infer: 25e3, price: 25 },
959
+ { queries: 2e3, infer: 1e5, price: 95 }
960
+ ];
961
+ function BuyInferModal({
962
+ isOpen,
963
+ onClose,
964
+ apiKey,
965
+ environment = "sandbox",
966
+ walletAddress,
967
+ inferPerQuery = 50,
968
+ className
969
+ }) {
970
+ const { buy, isBuying, status } = useBuyInfer({
971
+ apiKey,
972
+ environment,
973
+ walletAddress
974
+ });
975
+ const [selectedTier, setSelectedTier] = react.useState(1);
976
+ if (!isOpen) return null;
977
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(
978
+ "div",
979
+ {
980
+ className,
981
+ style: modalStyle,
982
+ onClick: (e) => e.stopPropagation(),
983
+ children: [
984
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "24px" }, children: [
985
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { style: { margin: 0, fontSize: "20px", color: "#f5f0e8" }, children: "Buy Query Credits" }),
986
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: onClose, style: closeStyle, children: "\xD7" })
987
+ ] }),
988
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "12px", marginBottom: "24px" }, children: TIERS.map((tier, i) => /* @__PURE__ */ jsxRuntime.jsxs(
989
+ "button",
990
+ {
991
+ onClick: () => setSelectedTier(i),
992
+ style: {
993
+ ...tierStyle,
994
+ borderColor: selectedTier === i ? "#d4a843" : "#333",
995
+ backgroundColor: selectedTier === i ? "#1a1a0a" : "#1a1a1a"
996
+ },
997
+ children: [
998
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontWeight: 600, fontSize: "16px", color: "#f5f0e8" }, children: [
999
+ tier.queries,
1000
+ " queries"
1001
+ ] }),
1002
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { color: "#d4a843", fontWeight: 700, fontSize: "18px" }, children: [
1003
+ "$",
1004
+ tier.price
1005
+ ] })
1006
+ ]
1007
+ },
1008
+ tier.queries
1009
+ )) }),
1010
+ /* @__PURE__ */ jsxRuntime.jsx(
1011
+ "button",
1012
+ {
1013
+ onClick: () => buy(TIERS[selectedTier].price),
1014
+ disabled: isBuying,
1015
+ style: {
1016
+ ...buyStyle,
1017
+ opacity: isBuying ? 0.7 : 1,
1018
+ cursor: isBuying ? "not-allowed" : "pointer"
1019
+ },
1020
+ children: isBuying ? "Processing..." : `Buy ${TIERS[selectedTier].queries} queries \u2014 $${TIERS[selectedTier].price}`
1021
+ }
1022
+ ),
1023
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "#666", fontSize: "12px", textAlign: "center", marginTop: "12px" }, children: "Powered by MoonPay. Visa, Mastercard, Apple Pay accepted." })
1024
+ ]
1025
+ }
1026
+ ) });
1027
+ }
1028
+ var overlayStyle = {
1029
+ position: "fixed",
1030
+ inset: 0,
1031
+ backgroundColor: "rgba(0, 0, 0, 0.7)",
1032
+ display: "flex",
1033
+ alignItems: "center",
1034
+ justifyContent: "center",
1035
+ zIndex: 9999
1036
+ };
1037
+ var modalStyle = {
1038
+ backgroundColor: "#111111",
1039
+ borderRadius: "16px",
1040
+ border: "1px solid #333",
1041
+ padding: "24px",
1042
+ width: "100%",
1043
+ maxWidth: "420px",
1044
+ fontFamily: "var(--font-body, Inter, sans-serif)"
1045
+ };
1046
+ var closeStyle = {
1047
+ background: "none",
1048
+ border: "none",
1049
+ color: "#666",
1050
+ fontSize: "24px",
1051
+ cursor: "pointer",
1052
+ padding: "4px 8px"
1053
+ };
1054
+ var tierStyle = {
1055
+ display: "flex",
1056
+ justifyContent: "space-between",
1057
+ alignItems: "center",
1058
+ padding: "16px 20px",
1059
+ borderRadius: "12px",
1060
+ border: "1px solid #333",
1061
+ cursor: "pointer",
1062
+ transition: "border-color 0.15s"
1063
+ };
1064
+ var buyStyle = {
1065
+ padding: "14px 32px",
1066
+ borderRadius: "8px",
1067
+ border: "none",
1068
+ backgroundColor: "#d4a843",
1069
+ color: "#0a0a0a",
1070
+ fontWeight: 700,
1071
+ fontSize: "16px",
1072
+ width: "100%"
1073
+ };
1074
+ function AppPaywall({ siteId, builderTenantId, children, onBlocked }) {
1075
+ const {
1076
+ hasAccess,
1077
+ queriesRemaining,
1078
+ paymentMode,
1079
+ unlockPriceCents,
1080
+ unlockPriceLabel,
1081
+ isLoading,
1082
+ checkout
1083
+ } = useAppAccess(siteId, { builderTenantId });
1084
+ const [serverBlocked, setServerBlocked] = react.useState(false);
1085
+ const [serverBlockReason, setServerBlockReason] = react.useState(null);
1086
+ react.useEffect(() => {
1087
+ function handlePaywall(e) {
1088
+ const detail = e.detail;
1089
+ if (!detail) return;
1090
+ if (detail.site_id && detail.site_id !== siteId) return;
1091
+ setServerBlocked(true);
1092
+ setServerBlockReason(detail.code || "payment_required");
1093
+ onBlocked?.(detail.code || "payment_required");
1094
+ }
1095
+ window.addEventListener("flowstack:app_paywall", handlePaywall);
1096
+ return () => window.removeEventListener("flowstack:app_paywall", handlePaywall);
1097
+ }, [siteId, onBlocked]);
1098
+ const showPaywall = serverBlocked || !isLoading && !hasAccess;
1099
+ if (!showPaywall) {
1100
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
1101
+ }
1102
+ const reason = serverBlockReason || (queriesRemaining === 0 ? "free_tier_exhausted" : "payment_required");
1103
+ const priceLabel = unlockPriceLabel || (unlockPriceCents ? `$${(unlockPriceCents / 100).toFixed(2)}` : "Unlock app");
1104
+ const showAgentOption = paymentMode === "agent" || paymentMode === "both";
1105
+ return /* @__PURE__ */ jsxRuntime.jsx(
1106
+ "div",
1107
+ {
1108
+ style: {
1109
+ position: "fixed",
1110
+ inset: 0,
1111
+ zIndex: 9999,
1112
+ display: "flex",
1113
+ alignItems: "center",
1114
+ justifyContent: "center",
1115
+ background: "rgba(0,0,0,0.72)",
1116
+ backdropFilter: "blur(4px)"
1117
+ },
1118
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
1119
+ "div",
1120
+ {
1121
+ style: {
1122
+ background: "#111",
1123
+ border: "1px solid #333",
1124
+ borderRadius: "12px",
1125
+ padding: "32px",
1126
+ maxWidth: "360px",
1127
+ width: "90vw",
1128
+ textAlign: "center",
1129
+ color: "#fff"
1130
+ },
1131
+ children: [
1132
+ /* @__PURE__ */ jsxRuntime.jsx(
1133
+ "p",
1134
+ {
1135
+ style: {
1136
+ fontSize: "10px",
1137
+ letterSpacing: "0.3em",
1138
+ textTransform: "uppercase",
1139
+ color: "#888",
1140
+ marginBottom: "12px"
1141
+ },
1142
+ children: reason === "free_tier_exhausted" ? "Free queries used" : "Access required"
1143
+ }
1144
+ ),
1145
+ reason === "free_tier_exhausted" && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "13px", color: "#aaa", marginBottom: "20px" }, children: "You've used your free queries for this month. Unlock unlimited access below." }),
1146
+ reason === "payment_required" && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "13px", color: "#aaa", marginBottom: "20px" }, children: "This app requires payment to access." }),
1147
+ /* @__PURE__ */ jsxRuntime.jsx(
1148
+ "button",
1149
+ {
1150
+ onClick: () => checkout(),
1151
+ style: {
1152
+ width: "100%",
1153
+ padding: "12px 24px",
1154
+ background: "#6366f1",
1155
+ color: "#fff",
1156
+ border: "none",
1157
+ borderRadius: "8px",
1158
+ fontSize: "13px",
1159
+ fontWeight: 600,
1160
+ cursor: "pointer",
1161
+ marginBottom: showAgentOption ? "8px" : "0"
1162
+ },
1163
+ children: priceLabel
1164
+ }
1165
+ ),
1166
+ showAgentOption && /* @__PURE__ */ jsxRuntime.jsx(
1167
+ "p",
1168
+ {
1169
+ style: {
1170
+ fontSize: "11px",
1171
+ color: "#666",
1172
+ cursor: "pointer",
1173
+ textDecoration: "underline"
1174
+ },
1175
+ onClick: () => {
1176
+ if (typeof window !== "undefined") {
1177
+ window.open(`https://openinferencefoundation.org/buy?returnTo=${encodeURIComponent(window.location.href)}`, "_blank");
1178
+ }
1179
+ },
1180
+ children: "Or pay with AGENT tokens"
1181
+ }
1182
+ )
1183
+ ]
1184
+ }
1185
+ )
1186
+ }
1187
+ );
1188
+ }
1189
+
1190
+ exports.AgentBalanceBadge = AgentBalanceBadge;
1191
+ exports.AppPaywall = AppPaywall;
1192
+ exports.BuyInferModal = BuyInferModal;
1193
+ exports.InferBalanceBadge = InferBalanceBadge;
1194
+ exports.LoginButton = LoginButton;
1195
+ exports.NeedsAgent = NeedsAgent;
1196
+ exports.PaymentRequired = PaymentRequired;
1197
+ exports.WalletProvider = WalletProvider;
1198
+ exports.useAgentBalance = useAgentBalance;
1199
+ exports.useAppAccess = useAppAccess;
1200
+ exports.useBuyInfer = useBuyInfer;
1201
+ exports.useDeposit = useDeposit;
1202
+ exports.useInferBalance = useInferBalance;
1203
+ exports.useWalletAuth = useWalletAuth;
1204
+ //# sourceMappingURL=index.js.map
1205
+ //# sourceMappingURL=index.js.map