@pollar/react 0.3.9 → 0.4.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.
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use client';
2
- import { PollarClient, StellarClient, StateStatus, STATE_VAR_CODES, PollarStateVar, isValidSession, WalletType } from '@pollar/core';
3
- import { createContext, useState, useEffect, useMemo, useContext, useRef } from 'react';
2
+ import { PollarClient, StellarClient, StateStatus, STATE_VAR_CODES, isValidSession, PollarStateVar, WalletType } from '@pollar/core';
3
+ import { createContext, useState, useEffect, useMemo, useContext, useRef, Component } from 'react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
 
6
6
  // src/context.tsx
@@ -10,6 +10,97 @@ var LOGO_POLLAR = "https://pollar.xyz/assets/logo_pollar.png";
10
10
  var LOGO_GITHUB = "https://pollar.xyz/assets/GitHub_Invertocat_White.png";
11
11
  var LOGO_FREIGHTER = "https://pollar.xyz/assets/logo_freighter.png";
12
12
  var LOGO_ALBEDO = "https://pollar.xyz/assets/logo_albedo.svg";
13
+ var ModalErrorBoundary = class extends Component {
14
+ constructor() {
15
+ super(...arguments);
16
+ this.state = { crashed: false };
17
+ }
18
+ static getDerivedStateFromError() {
19
+ return { crashed: true };
20
+ }
21
+ componentDidCatch(error) {
22
+ console.error("[Pollar] Modal crashed:", error);
23
+ }
24
+ render() {
25
+ if (this.state.crashed) {
26
+ this.props.onClose();
27
+ return null;
28
+ }
29
+ return this.props.children;
30
+ }
31
+ };
32
+ var PollarModalFooter = () => {
33
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-footer", children: [
34
+ /* @__PURE__ */ jsx("span", { className: "pollar-footer-protected", children: "Protected by" }),
35
+ /* @__PURE__ */ jsxs("div", { className: "pollar-footer-brand", children: [
36
+ /* @__PURE__ */ jsx("img", { src: LOGO_POLLAR, alt: "Pollar", className: "pollar-footer-logo" }),
37
+ /* @__PURE__ */ jsx("span", { className: "pollar-footer-name", children: "Pollar" }),
38
+ /* @__PURE__ */ jsxs("span", { className: "pollar-footer-version", children: [
39
+ "v",
40
+ "0.4.1"
41
+ ] })
42
+ ] })
43
+ ] });
44
+ };
45
+ var LOGIN_CODE_MESSAGES = {
46
+ NONE: { text: "" },
47
+ LOGOUT: { text: "Logged out" },
48
+ CREATE_SESSION_START: { text: "Starting session\u2026" },
49
+ CREATE_SESSION_ERROR: { text: "Failed to start session" },
50
+ CREATE_SESSION_SUCCESS: { text: "Session ready" },
51
+ EMAIL_AUTH_START: { text: "Sending code\u2026" },
52
+ EMAIL_AUTH_START_ERROR: { text: "Failed to send code" },
53
+ EMAIL_AUTH_START_SUCCESS: { text: "Code sent \u2014 check your inbox" },
54
+ EMAIL_AUTH_CODE_ERROR: { text: "Invalid code \u2014 try again" },
55
+ EMAIL_AUTH_CODE_SUCCESS: { text: "Code verified!" },
56
+ WALLET_AUTH_START: { text: "Connecting wallet\u2026" },
57
+ WALLET_AUTH_FREIGHTER_NOT_INSTALLED: { text: "Freighter is not installed" },
58
+ WALLET_AUTH_ALBEDO_NOT_INSTALLED: { text: "Albedo is not installed" },
59
+ WALLET_AUTH_CONNECTED: { text: "Wallet connected" },
60
+ WALLET_AUTH_LOGIN_START: { text: "Signing in with wallet\u2026" },
61
+ WALLET_AUTH_LOGIN_START_SUCCESS: { text: "Wallet signed in" },
62
+ WALLET_AUTH_LOGIN_START_ERROR: { text: "Failed to sign in with wallet" },
63
+ WALLET_AUTH_ERROR: { text: "Unknow wallet error" },
64
+ STREAM_POLL_START: { text: "Waiting for authentication\u2026" },
65
+ STREAM_POLL_EVENT: { text: "Waiting for authentication\u2026" },
66
+ STREAM_POLL_READY: { text: "Authenticated!" },
67
+ FETCH_SESSION_START: { text: "Loading session\u2026" },
68
+ FETCH_SESSION_SUCCESS: { text: "Welcome back!" },
69
+ FETCH_SESSION_ERROR: { text: "Failed to load session" },
70
+ RESTORED_SESSION_SUCCESS: { text: "Session restored" },
71
+ RESTORED_SESSION_ERROR: { text: "Failed to restore session" },
72
+ SESSION_STORED: { text: "Session saved" },
73
+ ERROR_UNKNOWN: { text: "Something went wrong" },
74
+ ABORTED: { text: "Login cancelled" },
75
+ // transaction
76
+ BUILD_TRANSACTION_START: { text: "Building transaction\u2026" },
77
+ BUILD_TRANSACTION_SUCCESS: { text: "Transaction built, ready to sign and send" },
78
+ BUILD_TRANSACTION_ERROR: { text: "Failed to build transaction" },
79
+ BUILD_TRANSACTION_ERROR_NO_WALLET: { text: "No wallet connected" },
80
+ SIGN_SEND_TRANSACTION_START: { text: "Signing and sending transaction\u2026" },
81
+ SIGN_SEND_TRANSACTION_SUCCESS: { text: "Transaction signed" },
82
+ SIGN_SEND_TRANSACTION_ERROR: { text: "Signing rejected" }
83
+ };
84
+ function ModalStatusBanner({ code, status, onCancel, onRetry }) {
85
+ if (!code) {
86
+ return /* @__PURE__ */ jsx("div", { className: "pollar-status" });
87
+ }
88
+ const { text } = LOGIN_CODE_MESSAGES[code] || { text: "" };
89
+ const isLoading = status === "LOADING";
90
+ const icon = status === "ERROR" ? /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
91
+ /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
92
+ /* @__PURE__ */ jsx("path", { d: "M4.5 4.5l5 5M9.5 4.5l-5 5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round" })
93
+ ] }) : status === "SUCCESS" ? /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
94
+ /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
95
+ /* @__PURE__ */ jsx("path", { d: "M3.5 7l2.5 2.5 4.5-5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
96
+ ] }) : status === "LOADING" ? /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "5.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeDasharray: "22 10" }) }) : null;
97
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-status", "data-kind": status, children: [
98
+ icon,
99
+ /* @__PURE__ */ jsx("span", { children: text }),
100
+ isLoading && onCancel && /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-status-cancel", onClick: onCancel, children: "Cancel" }),
101
+ status === StateStatus.ERROR && onRetry && /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-status-cancel", onClick: onRetry, children: "Retry" })
102
+ ] });
103
+ }
13
104
  function EmailCodeInput({ email, onSubmit }) {
14
105
  const [digits, setDigits] = useState(["", "", "", "", "", ""]);
15
106
  const inputRefs = useRef([]);
@@ -116,51 +207,6 @@ var GoogleButton = ({ disabled, onClick }) => {
116
207
  ] })
117
208
  ] });
118
209
  };
119
- var LOGIN_CODE_MESSAGES = {
120
- LOGOUT: { text: "Logged out" },
121
- CREATE_SESSION_START: { text: "Starting session\u2026" },
122
- CREATE_SESSION_ERROR: { text: "Failed to start session" },
123
- CREATE_SESSION_SUCCESS: { text: "Session ready" },
124
- EMAIL_AUTH_START: { text: "Sending code\u2026" },
125
- EMAIL_AUTH_START_ERROR: { text: "Failed to send code" },
126
- EMAIL_AUTH_START_SUCCESS: { text: "Code sent \u2014 check your inbox" },
127
- EMAIL_AUTH_CODE_ERROR: { text: "Invalid code \u2014 try again" },
128
- EMAIL_AUTH_CODE_SUCCESS: { text: "Code verified!" },
129
- WALLET_AUTH_START: { text: "Connecting wallet\u2026" },
130
- WALLET_AUTH_FREIGHTER_NOT_INSTALLED: { text: "Freighter is not installed" },
131
- WALLET_AUTH_ALBEDO_NOT_INSTALLED: { text: "Albedo is not installed" },
132
- WALLET_AUTH_CONNECTED: { text: "Wallet connected" },
133
- WALLET_AUTH_LOGIN_START: { text: "Signing in with wallet\u2026" },
134
- WALLET_AUTH_LOGIN_START_SUCCESS: { text: "Wallet signed in" },
135
- WALLET_AUTH_LOGIN_START_ERROR: { text: "Failed to sign in with wallet" },
136
- WALLET_AUTH_ERROR: { text: "Unknow wallet error" },
137
- STREAM_POLL_START: { text: "Waiting for authentication\u2026" },
138
- STREAM_POLL_EVENT: { text: "Waiting for authentication\u2026" },
139
- STREAM_POLL_READY: { text: "Authenticated!" },
140
- FETCH_SESSION_START: { text: "Loading session\u2026" },
141
- FETCH_SESSION_SUCCESS: { text: "Welcome back!" },
142
- FETCH_SESSION_ERROR: { text: "Failed to load session" },
143
- ERROR_UNKNOWN: { text: "Something went wrong" },
144
- ABORTED: { text: "Login cancelled" }
145
- };
146
- function LoginStatusBanner({ code, status, onCancel, onRetry }) {
147
- if (!code) return /* @__PURE__ */ jsx("div", { className: "pollar-status" });
148
- const { text } = LOGIN_CODE_MESSAGES[code] || { text: "" };
149
- const isLoading = status === StateStatus.LOADING;
150
- const icon = status === StateStatus.ERROR ? /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
151
- /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
152
- /* @__PURE__ */ jsx("path", { d: "M4.5 4.5l5 5M9.5 4.5l-5 5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round" })
153
- ] }) : status === StateStatus.SUCCESS ? /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
154
- /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
155
- /* @__PURE__ */ jsx("path", { d: "M3.5 7l2.5 2.5 4.5-5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
156
- ] }) : status === StateStatus.LOADING ? /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "5.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeDasharray: "22 10" }) }) : null;
157
- return /* @__PURE__ */ jsxs("div", { className: "pollar-status", "data-kind": status, children: [
158
- icon,
159
- /* @__PURE__ */ jsx("span", { children: text }),
160
- isLoading && onCancel && /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-status-cancel", onClick: onCancel, children: "Cancel" }),
161
- status === StateStatus.ERROR && /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-status-cancel", onClick: onRetry, children: "Retry" })
162
- ] });
163
- }
164
210
  function LoginModalTemplate({
165
211
  theme,
166
212
  accentColor,
@@ -243,22 +289,12 @@ function LoginModalTemplate({
243
289
  ] })
244
290
  ] })
245
291
  ] }),
246
- /* @__PURE__ */ jsx(LoginStatusBanner, { code: loginStateCode, status, onCancel: () => cancelLoginRef.current?.(), onRetry }),
247
- /* @__PURE__ */ jsxs("div", { className: "pollar-footer", children: [
248
- /* @__PURE__ */ jsx("span", { className: "pollar-footer-protected", children: "Protected by" }),
249
- /* @__PURE__ */ jsxs("div", { className: "pollar-footer-brand", children: [
250
- /* @__PURE__ */ jsx("img", { src: LOGO_POLLAR, alt: "Pollar", className: "pollar-footer-logo" }),
251
- /* @__PURE__ */ jsx("span", { className: "pollar-footer-name", children: "Pollar" }),
252
- /* @__PURE__ */ jsxs("span", { className: "pollar-footer-version", children: [
253
- "v",
254
- "0.3.9"
255
- ] })
256
- ] })
257
- ] })
292
+ /* @__PURE__ */ jsx(ModalStatusBanner, { code: loginStateCode, status, onCancel: () => cancelLoginRef.current?.(), onRetry }),
293
+ /* @__PURE__ */ jsx(PollarModalFooter, {})
258
294
  ] });
259
295
  }
260
296
  function isLoginCode(code) {
261
- return Object.values(STATE_VAR_CODES[PollarStateVar.LOGIN]).includes(code);
297
+ return Object.values(STATE_VAR_CODES[PollarStateVar.AUTHENTICATION]).includes(code);
262
298
  }
263
299
  function LoginModal({ onClose }) {
264
300
  const [email, setEmail] = useState("");
@@ -270,20 +306,20 @@ function LoginModal({ onClose }) {
270
306
  const [clientSessionId, setClientSessionId] = useState(null);
271
307
  useEffect(() => {
272
308
  return getClient().onStateChange((stateEntry) => {
273
- if (stateEntry.var === PollarStateVar.LOGIN && isLoginCode(stateEntry.code)) {
309
+ if (stateEntry.var === PollarStateVar.AUTHENTICATION && isLoginCode(stateEntry.code)) {
274
310
  setLoginStateCode(stateEntry.code);
275
311
  setStatus(stateEntry.status);
276
- if (stateEntry.code === STATE_VAR_CODES[PollarStateVar.LOGIN].STREAM_POLL_START) {
312
+ if (stateEntry.code === STATE_VAR_CODES[PollarStateVar.AUTHENTICATION].STREAM_POLL_START) {
277
313
  const data = stateEntry.data;
278
314
  setClientSessionId(data.clientSessionId);
279
315
  }
280
- if (stateEntry.code === STATE_VAR_CODES[PollarStateVar.LOGIN].STREAM_POLL_EVENT) {
316
+ if (stateEntry.code === STATE_VAR_CODES[PollarStateVar.AUTHENTICATION].STREAM_POLL_EVENT) {
281
317
  const data = stateEntry.data;
282
318
  if (data?.status === "AWAITING_EMAIL") {
283
319
  setAwaitingEmailCode(true);
284
320
  }
285
321
  }
286
- if (stateEntry.code === STATE_VAR_CODES[PollarStateVar.LOGIN].FETCH_SESSION_SUCCESS) {
322
+ if (stateEntry.code === STATE_VAR_CODES[PollarStateVar.AUTHENTICATION].FETCH_SESSION_SUCCESS) {
287
323
  setAwaitingEmailCode(false);
288
324
  setTimeout(onClose, 1e3);
289
325
  }
@@ -353,6 +389,203 @@ function LoginModal({ onClose }) {
353
389
  }
354
390
  ) });
355
391
  }
392
+ function TransactionModalTemplate({
393
+ theme,
394
+ accentColor,
395
+ transactionStateCode,
396
+ status,
397
+ buildResult,
398
+ submitResult,
399
+ onClose,
400
+ onSignAndSend,
401
+ onRetrySignAndSend
402
+ }) {
403
+ const isDark = theme === "dark";
404
+ const cssVars = {
405
+ "--pollar-accent": accentColor,
406
+ "--pollar-buttons-border-radius": "8px",
407
+ "--pollar-buttons-height": "44px",
408
+ "--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
409
+ "--pollar-border": isDark ? "#374151" : "#e5e7eb",
410
+ "--pollar-text": isDark ? "#ffffff" : "#111827",
411
+ "--pollar-muted": isDark ? "#9ca3af" : "#6b7280",
412
+ "--pollar-input-bg": isDark ? "#374151" : "rgba(0,0,0,0.04)",
413
+ "--pollar-error-text": isDark ? "#f87171" : "#dc2626",
414
+ "--pollar-success-text": isDark ? "#4ade80" : "#16a34a"
415
+ };
416
+ const [showXdr, setShowXdr] = useState(false);
417
+ const [copied, setCopied] = useState(false);
418
+ function handleCopyHash() {
419
+ if (!submitResult) return;
420
+ navigator.clipboard.writeText(submitResult.hash).then(() => {
421
+ setCopied(true);
422
+ setTimeout(() => setCopied(false), 2e3);
423
+ });
424
+ }
425
+ const explorerNetwork = buildResult?.summary.network?.toLowerCase().includes("testnet") ? "testnet" : "public";
426
+ const explorerUrl = submitResult ? `https://stellar.expert/explorer/${explorerNetwork}/tx/${submitResult.hash}` : null;
427
+ transactionStateCode.includes("ERROR");
428
+ transactionStateCode.includes("SUCCESS");
429
+ const isBuilt = buildResult && transactionStateCode === "BUILD_TRANSACTION_SUCCESS";
430
+ const isDone = submitResult && transactionStateCode === "SIGN_SEND_TRANSACTION_START";
431
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-tx-modal", "data-theme": theme, style: cssVars, onClick: (e) => e.stopPropagation(), children: [
432
+ /* @__PURE__ */ jsxs("div", { className: "pollar-tx-header", children: [
433
+ /* @__PURE__ */ jsx("h2", { className: "pollar-tx-title", children: "Transaction" }),
434
+ /* @__PURE__ */ jsx("button", { className: "pollar-tx-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
435
+ ] }),
436
+ isBuilt && /* @__PURE__ */ jsxs(Fragment, { children: [
437
+ /* @__PURE__ */ jsxs("div", { className: "pollar-tx-summary", children: [
438
+ /* @__PURE__ */ jsx("p", { className: "pollar-tx-summary-title", children: "Details" }),
439
+ /* @__PURE__ */ jsx("ul", { className: "pollar-tx-summary-lines", children: buildResult.summary.lines.map((line, i) => /* @__PURE__ */ jsx("li", { className: "pollar-tx-summary-line", children: line }, i)) })
440
+ ] }),
441
+ /* @__PURE__ */ jsxs("div", { className: "pollar-tx-meta", children: [
442
+ /* @__PURE__ */ jsxs("div", { className: "pollar-tx-meta-item", children: [
443
+ /* @__PURE__ */ jsx("span", { className: "pollar-tx-meta-label", children: "Network" }),
444
+ /* @__PURE__ */ jsx("span", { className: "pollar-tx-meta-value", children: buildResult.summary.network })
445
+ ] }),
446
+ /* @__PURE__ */ jsxs("div", { className: "pollar-tx-meta-item", children: [
447
+ /* @__PURE__ */ jsx("span", { className: "pollar-tx-meta-label", children: "Fee" }),
448
+ /* @__PURE__ */ jsx("span", { className: "pollar-tx-meta-value", children: buildResult.summary.fee })
449
+ ] })
450
+ ] }),
451
+ /* @__PURE__ */ jsxs("div", { className: "pollar-tx-xdr", children: [
452
+ /* @__PURE__ */ jsxs("button", { className: "pollar-tx-xdr-toggle", onClick: () => setShowXdr((v) => !v), children: [
453
+ /* @__PURE__ */ jsx(
454
+ "svg",
455
+ {
456
+ width: "12",
457
+ height: "12",
458
+ viewBox: "0 0 12 12",
459
+ fill: "none",
460
+ "aria-hidden": true,
461
+ style: { transform: showXdr ? "rotate(90deg)" : "rotate(0deg)", transition: "transform 150ms" },
462
+ children: /* @__PURE__ */ jsx("path", { d: "M4 2l4 4-4 4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
463
+ }
464
+ ),
465
+ "Raw transaction (XDR)"
466
+ ] }),
467
+ showXdr && /* @__PURE__ */ jsx("pre", { className: "pollar-tx-xdr-content", children: buildResult.unsignedXdr })
468
+ ] })
469
+ ] }),
470
+ submitResult && transactionStateCode === "SIGN_SEND_TRANSACTION_SUCCESS" && /* @__PURE__ */ jsxs("div", { className: "pollar-tx-result", children: [
471
+ /* @__PURE__ */ jsx("span", { className: "pollar-tx-result-label", children: "Transaction hash" }),
472
+ /* @__PURE__ */ jsx("span", { className: "pollar-tx-result-hash", children: submitResult.hash }),
473
+ /* @__PURE__ */ jsxs("div", { className: "pollar-tx-result-actions", children: [
474
+ /* @__PURE__ */ jsx("button", { className: "pollar-tx-result-btn", onClick: handleCopyHash, children: copied ? /* @__PURE__ */ jsxs(Fragment, { children: [
475
+ /* @__PURE__ */ jsxs("svg", { width: "13", height: "13", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
476
+ /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
477
+ /* @__PURE__ */ jsx(
478
+ "path",
479
+ {
480
+ d: "M3.5 7l2.5 2.5 4.5-5",
481
+ stroke: "white",
482
+ strokeWidth: "1.5",
483
+ strokeLinecap: "round",
484
+ strokeLinejoin: "round"
485
+ }
486
+ )
487
+ ] }),
488
+ "Copied!"
489
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
490
+ /* @__PURE__ */ jsxs("svg", { width: "13", height: "13", viewBox: "0 0 13 13", fill: "none", "aria-hidden": true, children: [
491
+ /* @__PURE__ */ jsx("rect", { x: "4", y: "4", width: "8", height: "8", rx: "1.5", stroke: "currentColor", strokeWidth: "1.5" }),
492
+ /* @__PURE__ */ jsx(
493
+ "path",
494
+ {
495
+ d: "M3 9H2a1 1 0 01-1-1V2a1 1 0 011-1h6a1 1 0 011 1v1",
496
+ stroke: "currentColor",
497
+ strokeWidth: "1.5",
498
+ strokeLinecap: "round"
499
+ }
500
+ )
501
+ ] }),
502
+ "Copy hash"
503
+ ] }) }),
504
+ explorerUrl && /* @__PURE__ */ jsxs("a", { className: "pollar-tx-result-btn", href: explorerUrl, target: "_blank", rel: "noopener noreferrer", children: [
505
+ /* @__PURE__ */ jsxs("svg", { width: "13", height: "13", viewBox: "0 0 13 13", fill: "none", "aria-hidden": true, children: [
506
+ /* @__PURE__ */ jsx(
507
+ "path",
508
+ {
509
+ d: "M5 2H2a1 1 0 00-1 1v8a1 1 0 001 1h8a1 1 0 001-1V8",
510
+ stroke: "currentColor",
511
+ strokeWidth: "1.5",
512
+ strokeLinecap: "round"
513
+ }
514
+ ),
515
+ /* @__PURE__ */ jsx(
516
+ "path",
517
+ {
518
+ d: "M8 1h4m0 0v4m0-4L6 7",
519
+ stroke: "currentColor",
520
+ strokeWidth: "1.5",
521
+ strokeLinecap: "round",
522
+ strokeLinejoin: "round"
523
+ }
524
+ )
525
+ ] }),
526
+ "View on Explorer"
527
+ ] })
528
+ ] })
529
+ ] }),
530
+ isBuilt && /* @__PURE__ */ jsx("button", { className: "pollar-tx-sign-btn", onClick: onSignAndSend, children: "Sign & Send" }),
531
+ isDone && /* @__PURE__ */ jsx("button", { className: "pollar-tx-sign-btn", onClick: onClose, children: "Done" }),
532
+ /* @__PURE__ */ jsx(
533
+ ModalStatusBanner,
534
+ {
535
+ code: transactionStateCode,
536
+ status
537
+ }
538
+ ),
539
+ /* @__PURE__ */ jsx(PollarModalFooter, {})
540
+ ] });
541
+ }
542
+ var isTxBuildResponseContent = (data) => {
543
+ if (!data || typeof data !== "object") return false;
544
+ const d = data;
545
+ return typeof d.unsignedXdr === "string" && typeof d.networkPassphrase === "string" && typeof d.estimatedFee === "string" && d.summary !== null && typeof d.summary === "object";
546
+ };
547
+ var isTxSignSendResponseContent = (data) => {
548
+ if (!data || typeof data !== "object") return false;
549
+ const d = data;
550
+ return typeof d.hash === "string" && (d.status === "PENDING" || d.status === "SUCCESS" || d.status === "FAILED");
551
+ };
552
+ function TransactionModal({ onClose }) {
553
+ const {
554
+ getClient,
555
+ styles,
556
+ state: { transaction }
557
+ } = usePollar();
558
+ const { theme = "light", accentColor = "#005DB4" } = styles;
559
+ let buildResult = null;
560
+ const transactionStateCode = transaction.code;
561
+ const content = transaction.data?.content;
562
+ if (isTxBuildResponseContent(content)) {
563
+ buildResult = content;
564
+ }
565
+ let submitResult = null;
566
+ if (isTxSignSendResponseContent(content)) {
567
+ submitResult = content;
568
+ }
569
+ async function handleSignAndSend() {
570
+ if (buildResult) {
571
+ await getClient().submitTx(buildResult.unsignedXdr);
572
+ }
573
+ }
574
+ return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", onClick: onClose, children: /* @__PURE__ */ jsx(
575
+ TransactionModalTemplate,
576
+ {
577
+ theme,
578
+ accentColor,
579
+ transactionStateCode,
580
+ status: transaction.status,
581
+ buildResult,
582
+ submitResult,
583
+ onClose,
584
+ onSignAndSend: handleSignAndSend,
585
+ onRetrySignAndSend: handleSignAndSend
586
+ }
587
+ ) });
588
+ }
356
589
  var emptyResponse = {
357
590
  application: {
358
591
  name: ""
@@ -361,7 +594,7 @@ var emptyResponse = {
361
594
  };
362
595
  async function fetchRemoteConfig(api) {
363
596
  try {
364
- const { data, error } = await api.GET(`/config`);
597
+ const { data, error } = await api.GET(`/applications/config`);
365
598
  if (!data || error) {
366
599
  return emptyResponse;
367
600
  }
@@ -376,16 +609,23 @@ function PollarProvider({ config, styles: propStyles, children }) {
376
609
  const [stellarClient] = useState(() => new StellarClient(config.stellarNetwork || "testnet"));
377
610
  const [sessionState, setSessionState] = useState(null);
378
611
  const [state, setState] = useState({
379
- [PollarStateVar.LOGIN]: {
380
- var: PollarStateVar.LOGIN,
381
- code: STATE_VAR_CODES[PollarStateVar.LOGIN].NONE,
612
+ network: {
613
+ var: "network",
614
+ code: STATE_VAR_CODES.network.NONE,
615
+ status: StateStatus.NONE,
616
+ level: "info",
617
+ ts: 0
618
+ },
619
+ authentication: {
620
+ var: "authentication",
621
+ code: STATE_VAR_CODES.authentication.NONE,
382
622
  status: StateStatus.NONE,
383
623
  level: "info",
384
624
  ts: 0
385
625
  },
386
- [PollarStateVar.WALLET_ADDRESS]: {
387
- var: PollarStateVar.WALLET_ADDRESS,
388
- code: STATE_VAR_CODES[PollarStateVar.WALLET_ADDRESS].NONE,
626
+ transaction: {
627
+ var: "transaction",
628
+ code: STATE_VAR_CODES.transaction.NONE,
389
629
  status: StateStatus.NONE,
390
630
  level: "info",
391
631
  ts: 0
@@ -404,8 +644,8 @@ function PollarProvider({ config, styles: propStyles, children }) {
404
644
  }
405
645
  return prevState;
406
646
  });
407
- if (stateEntry.var === PollarStateVar.WALLET_ADDRESS) {
408
- if (stateEntry.code === STATE_VAR_CODES[PollarStateVar.WALLET_ADDRESS].UPDATED_ADDRESS && isValidSession(stateEntry.data)) {
647
+ if (stateEntry.var === "authentication") {
648
+ if ((stateEntry.code === STATE_VAR_CODES.authentication.SESSION_STORED || STATE_VAR_CODES.authentication.RESTORED_SESSION_SUCCESS) && isValidSession(stateEntry.data)) {
409
649
  setSessionState((prevState) => {
410
650
  if (JSON.stringify(prevState) !== JSON.stringify(stateEntry.data)) {
411
651
  return stateEntry.data;
@@ -413,9 +653,9 @@ function PollarProvider({ config, styles: propStyles, children }) {
413
653
  return prevState;
414
654
  });
415
655
  }
416
- }
417
- if (stateEntry.var === PollarStateVar.WALLET_ADDRESS && stateEntry.code === STATE_VAR_CODES[PollarStateVar.WALLET_ADDRESS].REMOVED_ADDRESS || stateEntry.var === PollarStateVar.LOGIN && stateEntry.code === STATE_VAR_CODES[PollarStateVar.LOGIN].LOGOUT) {
418
- setSessionState(null);
656
+ if (stateEntry.code === STATE_VAR_CODES.authentication.LOGOUT) {
657
+ setSessionState(null);
658
+ }
419
659
  }
420
660
  });
421
661
  }, [pollarClient]);
@@ -431,31 +671,43 @@ function PollarProvider({ config, styles: propStyles, children }) {
431
671
  setStyles(propStyles ?? {});
432
672
  });
433
673
  }, [pollarClient]);
434
- const [modalOpen, setModalOpen] = useState(false);
674
+ const [loginModalOpen, setLoginModalOpen] = useState(false);
675
+ const [transactionModalOpen, setTransactionModalOpen] = useState(false);
435
676
  const contextValue = useMemo(
436
677
  () => ({
437
678
  walletAddress: sessionState?.wallet?.publicKey || "",
438
679
  getClient: () => pollarClient,
439
- openLoginModal: () => setModalOpen(true),
440
- isAuthenticated: pollarClient.isAuthenticated(),
680
+ // client
681
+ state,
441
682
  login: (options) => pollarClient.login(options),
442
683
  logout: () => pollarClient.logout(),
684
+ isAuthenticated: pollarClient.isAuthenticated(),
685
+ buildTx: (operation, params, options) => pollarClient.buildTx(operation, params, options),
686
+ submitTx: (signedXdr) => pollarClient.submitTx(signedXdr),
687
+ // react
688
+ sendTransaction: (operation, params, options) => {
689
+ void pollarClient.buildTx(operation, params, options);
690
+ setTransactionModalOpen(true);
691
+ },
692
+ openTransactionModal: () => setTransactionModalOpen(true),
693
+ openLoginModal: () => setLoginModalOpen(true),
443
694
  config: remoteConfig,
444
- state,
445
695
  styles,
696
+ // stellar
446
697
  async getBalance(publicKey) {
447
698
  const pk = publicKey || sessionState?.wallet?.publicKey;
448
699
  if (pk) {
449
- return stellarClient.getBalances(pk);
700
+ return await stellarClient.getBalances(pk);
450
701
  }
451
- return null;
702
+ return { success: false, errorCode: "NO_WALLET_FOUND", balances: [] };
452
703
  }
453
704
  }),
454
705
  [sessionState, remoteConfig, styles, pollarClient, state]
455
706
  );
456
707
  return /* @__PURE__ */ jsxs(PollarContext.Provider, { value: contextValue, children: [
457
708
  children,
458
- modalOpen && /* @__PURE__ */ jsx(LoginModal, { onClose: () => setModalOpen(false) })
709
+ loginModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setLoginModalOpen(false), children: /* @__PURE__ */ jsx(LoginModal, { onClose: () => setLoginModalOpen(false) }) }),
710
+ transactionModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setTransactionModalOpen(false), children: /* @__PURE__ */ jsx(TransactionModal, { onClose: () => setTransactionModalOpen(false) }) })
459
711
  ] });
460
712
  }
461
713
  function usePollar() {