@usdctofiat/offramp 1.3.0 → 2.0.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.js CHANGED
@@ -1,11 +1,14 @@
1
1
  import {
2
2
  CURRENCIES,
3
3
  ESCROW_ADDRESS,
4
+ MakersCreateError,
4
5
  Offramp,
5
6
  OfframpError,
7
+ PEER_EXTENSION_CHROME_URL,
6
8
  PLATFORMS,
7
9
  close,
8
10
  createOfframp,
11
+ createPeerExtensionSdk,
9
12
  createTelemetryContext,
10
13
  delegate,
11
14
  deposits,
@@ -13,17 +16,33 @@ import {
13
16
  emitEvent,
14
17
  enableOtc,
15
18
  getOtcLink,
19
+ getPeerExtensionRegistrationInfo,
20
+ getPeerExtensionState,
21
+ isPeerExtensionAvailable,
22
+ isPeerExtensionRegistrationError,
23
+ normalizePaypalMeUsername,
16
24
  offramp,
25
+ openPeerExtensionInstallPage,
26
+ peerExtensionSdk,
17
27
  sanitizeAttributionId,
18
28
  sendTelemetryEvent,
19
29
  undelegate
20
- } from "./chunk-JQBKGGI2.js";
30
+ } from "./chunk-747S3WWB.js";
21
31
 
22
32
  // src/types.ts
23
33
  var OFFRAMP_ERROR_CODES = {
24
34
  VALIDATION: "VALIDATION",
25
35
  APPROVAL_FAILED: "APPROVAL_FAILED",
26
36
  REGISTRATION_FAILED: "REGISTRATION_FAILED",
37
+ /**
38
+ * Curator rejected the maker because the user has not registered this
39
+ * handle in the Peer extension yet. Thrown from `offramp()` for PayPal
40
+ * and Wise when `/v2/makers/create` returns 400 or a "creating the maker"
41
+ * message. Recover by prompting the user through the Peer extension via
42
+ * `usePeerExtensionRegistration(platform)` (React) or `peerExtensionSdk`
43
+ * directly, then call `offramp()` again.
44
+ */
45
+ EXTENSION_REGISTRATION_REQUIRED: "EXTENSION_REGISTRATION_REQUIRED",
27
46
  DEPOSIT_FAILED: "DEPOSIT_FAILED",
28
47
  CONFIRMATION_FAILED: "CONFIRMATION_FAILED",
29
48
  DELEGATION_FAILED: "DELEGATION_FAILED",
@@ -33,12 +52,15 @@ var OFFRAMP_ERROR_CODES = {
33
52
  export {
34
53
  CURRENCIES,
35
54
  ESCROW_ADDRESS,
55
+ MakersCreateError,
36
56
  OFFRAMP_ERROR_CODES,
37
57
  Offramp,
38
58
  OfframpError,
59
+ PEER_EXTENSION_CHROME_URL,
39
60
  PLATFORMS,
40
61
  close,
41
62
  createOfframp,
63
+ createPeerExtensionSdk,
42
64
  createTelemetryContext,
43
65
  delegate,
44
66
  deposits,
@@ -46,7 +68,14 @@ export {
46
68
  emitEvent,
47
69
  enableOtc,
48
70
  getOtcLink,
71
+ getPeerExtensionRegistrationInfo,
72
+ getPeerExtensionState,
73
+ isPeerExtensionAvailable,
74
+ isPeerExtensionRegistrationError,
75
+ normalizePaypalMeUsername,
49
76
  offramp,
77
+ openPeerExtensionInstallPage,
78
+ peerExtensionSdk,
50
79
  sanitizeAttributionId,
51
80
  sendTelemetryEvent,
52
81
  undelegate
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { PlatformEntry } from \"./platforms\";\nimport type { CurrencyEntry } from \"./currencies\";\n\nexport const OFFRAMP_ERROR_CODES = {\n VALIDATION: \"VALIDATION\",\n APPROVAL_FAILED: \"APPROVAL_FAILED\",\n REGISTRATION_FAILED: \"REGISTRATION_FAILED\",\n DEPOSIT_FAILED: \"DEPOSIT_FAILED\",\n CONFIRMATION_FAILED: \"CONFIRMATION_FAILED\",\n DELEGATION_FAILED: \"DELEGATION_FAILED\",\n USER_CANCELLED: \"USER_CANCELLED\",\n UNSUPPORTED: \"UNSUPPORTED\",\n} as const;\n\nexport type OfframpErrorCode = (typeof OFFRAMP_ERROR_CODES)[keyof typeof OFFRAMP_ERROR_CODES];\n\nexport interface OfframpParams {\n /** USDC amount as decimal string, min 1. */\n amount: string;\n /** Payment platform — use `PLATFORMS.REVOLUT` etc. */\n platform: PlatformEntry;\n /** Fiat currency — use `CURRENCIES.EUR` etc. */\n currency: CurrencyEntry;\n /** Platform-specific identifier (username, email, IBAN). */\n identifier: string;\n /** Optional: restrict the deposit to this taker wallet (OTC private order). */\n otcTaker?: string;\n /** Optional SDK-only referral metadata for telemetry attribution. */\n referralId?: string;\n /** Optional SDK-only integrator metadata for telemetry attribution. */\n integratorId?: string;\n /** Optional per-wallet key to replay the first successful result for 10 minutes. */\n idempotencyKey?: string;\n}\n\nexport interface OfframpResult {\n depositId: string;\n txHash: string;\n /** Whether an existing undelegated deposit was resumed. */\n resumed: boolean;\n /** OTC link for the taker, present when `otcTaker` was provided. */\n otcLink?: string;\n}\n\nexport type OfframpStep =\n | \"approving\"\n | \"registering\"\n | \"depositing\"\n | \"confirming\"\n | \"delegating\"\n | \"restricting\"\n | \"resuming\"\n | \"done\";\n\nexport type OfframpState =\n | \"idle\"\n | \"approving\"\n | \"registering\"\n | \"depositing\"\n | \"confirming\"\n | \"delegating\"\n | \"done\"\n | \"error\";\n\nexport interface OfframpProgress {\n step: OfframpStep;\n txHash?: string;\n depositId?: string;\n}\n\nexport type OnProgress = (progress: OfframpProgress) => void;\n\nexport type DepositStatus = \"active\" | \"empty\" | \"closed\";\n\nexport interface OfframpQuoteInput {\n amount: string;\n currency: CurrencyEntry;\n platform: PlatformEntry;\n}\n\nexport interface OfframpQuote {\n amountUsdc: number;\n expectedFiat: number;\n effectiveRate: number;\n vaultSpreadBps: number;\n}\n\nexport interface OfframpVaultStatus {\n rateManagerId: string;\n rateManagerAddress: string;\n feeRateBps: number;\n escrow: string;\n isActive: boolean;\n}\n\nexport interface OfframpCreateOptions {\n integratorId?: string;\n referralId?: string;\n telemetry?: boolean;\n}\n\nexport interface DepositInfo {\n /** Numeric deposit ID. Pass this to `close()`. */\n depositId: string;\n /** Composite ID (escrowAddress_depositId). */\n compositeId: string;\n /** Creation transaction hash. */\n txHash?: string;\n status: DepositStatus;\n remainingUsdc: number;\n outstandingUsdc: number;\n totalTakenUsdc: number;\n fulfilledIntents: number;\n paymentMethods: string[];\n currencies: string[];\n rateSource: string;\n delegated: boolean;\n escrowAddress: string;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAGO,IAAM,sBAAsB;AAAA,EACjC,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,gBAAgB;AAAA,EAChB,qBAAqB;AAAA,EACrB,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,aAAa;AACf;","names":[]}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { PlatformEntry } from \"./platforms\";\nimport type { CurrencyEntry } from \"./currencies\";\n\nexport const OFFRAMP_ERROR_CODES = {\n VALIDATION: \"VALIDATION\",\n APPROVAL_FAILED: \"APPROVAL_FAILED\",\n REGISTRATION_FAILED: \"REGISTRATION_FAILED\",\n /**\n * Curator rejected the maker because the user has not registered this\n * handle in the Peer extension yet. Thrown from `offramp()` for PayPal\n * and Wise when `/v2/makers/create` returns 400 or a \"creating the maker\"\n * message. Recover by prompting the user through the Peer extension via\n * `usePeerExtensionRegistration(platform)` (React) or `peerExtensionSdk`\n * directly, then call `offramp()` again.\n */\n EXTENSION_REGISTRATION_REQUIRED: \"EXTENSION_REGISTRATION_REQUIRED\",\n DEPOSIT_FAILED: \"DEPOSIT_FAILED\",\n CONFIRMATION_FAILED: \"CONFIRMATION_FAILED\",\n DELEGATION_FAILED: \"DELEGATION_FAILED\",\n USER_CANCELLED: \"USER_CANCELLED\",\n UNSUPPORTED: \"UNSUPPORTED\",\n} as const;\n\nexport type OfframpErrorCode = (typeof OFFRAMP_ERROR_CODES)[keyof typeof OFFRAMP_ERROR_CODES];\n\nexport interface OfframpParams {\n /** USDC amount as decimal string, min 1. */\n amount: string;\n /** Payment platform — use `PLATFORMS.REVOLUT` etc. */\n platform: PlatformEntry;\n /** Fiat currency — use `CURRENCIES.EUR` etc. */\n currency: CurrencyEntry;\n /** Platform-specific identifier (username, email, IBAN). */\n identifier: string;\n /** Optional: restrict the deposit to this taker wallet (OTC private order). */\n otcTaker?: string;\n /** Optional SDK-only referral metadata for telemetry attribution. */\n referralId?: string;\n /** Optional SDK-only integrator metadata for telemetry attribution. */\n integratorId?: string;\n /** Optional per-wallet key to replay the first successful result for 10 minutes. */\n idempotencyKey?: string;\n}\n\nexport interface OfframpResult {\n depositId: string;\n txHash: string;\n /** Whether an existing undelegated deposit was resumed. */\n resumed: boolean;\n /** OTC link for the taker, present when `otcTaker` was provided. */\n otcLink?: string;\n}\n\nexport type OfframpStep =\n | \"approving\"\n | \"registering\"\n | \"depositing\"\n | \"confirming\"\n | \"delegating\"\n | \"restricting\"\n | \"resuming\"\n | \"done\";\n\nexport type OfframpState =\n | \"idle\"\n | \"approving\"\n | \"registering\"\n | \"depositing\"\n | \"confirming\"\n | \"delegating\"\n | \"done\"\n | \"error\";\n\nexport interface OfframpProgress {\n step: OfframpStep;\n txHash?: string;\n depositId?: string;\n}\n\nexport type OnProgress = (progress: OfframpProgress) => void;\n\nexport type DepositStatus = \"active\" | \"empty\" | \"closed\";\n\nexport interface OfframpQuoteInput {\n amount: string;\n currency: CurrencyEntry;\n platform: PlatformEntry;\n}\n\nexport interface OfframpQuote {\n amountUsdc: number;\n expectedFiat: number;\n effectiveRate: number;\n vaultSpreadBps: number;\n}\n\nexport interface OfframpVaultStatus {\n rateManagerId: string;\n rateManagerAddress: string;\n feeRateBps: number;\n escrow: string;\n isActive: boolean;\n}\n\nexport interface OfframpCreateOptions {\n integratorId?: string;\n referralId?: string;\n telemetry?: boolean;\n}\n\nexport interface DepositInfo {\n /** Numeric deposit ID. Pass this to `close()`. */\n depositId: string;\n /** Composite ID (escrowAddress_depositId). */\n compositeId: string;\n /** Creation transaction hash. */\n txHash?: string;\n status: DepositStatus;\n remainingUsdc: number;\n outstandingUsdc: number;\n totalTakenUsdc: number;\n fulfilledIntents: number;\n paymentMethods: string[];\n currencies: string[];\n rateSource: string;\n delegated: boolean;\n escrowAddress: string;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGO,IAAM,sBAAsB;AAAA,EACjC,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASrB,iCAAiC;AAAA,EACjC,gBAAgB;AAAA,EAChB,qBAAqB;AAAA,EACrB,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,aAAa;AACf;","names":[]}
package/dist/react.cjs CHANGED
@@ -20,7 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/react.ts
21
21
  var react_exports = {};
22
22
  __export(react_exports, {
23
- useOfframp: () => useOfframp
23
+ useOfframp: () => useOfframp,
24
+ usePeerExtensionRegistration: () => usePeerExtensionRegistration
24
25
  });
25
26
  module.exports = __toCommonJS(react_exports);
26
27
 
@@ -169,6 +170,17 @@ function resolveSupportedCurrencies(platform) {
169
170
  }
170
171
  return Array.from(codes).sort();
171
172
  }
173
+ function normalizePaypalMeUsername(value) {
174
+ const trimmed = value.trim();
175
+ if (!trimmed) return "";
176
+ const withoutProtocol = trimmed.replace(/^https?:\/\//i, "").replace(/^www\./i, "");
177
+ if (/^paypal\.me(?:[?#].*)?$/i.test(withoutProtocol)) return "";
178
+ const withoutDomain = withoutProtocol.replace(/^paypal\.me\//i, "");
179
+ const [pathWithoutQuery] = withoutDomain.split(/[?#]/, 1);
180
+ const sanitizedPath = pathWithoutQuery.replace(/^\/+/, "");
181
+ const [username] = sanitizedPath.split("/", 1);
182
+ return username.replace(/^@+/, "").trim().toLowerCase();
183
+ }
172
184
  var BLUEPRINTS = {
173
185
  venmo: {
174
186
  id: "venmo",
@@ -216,7 +228,13 @@ var BLUEPRINTS = {
216
228
  placeholder: "wisetag (no @)",
217
229
  helperText: "Your Wise @wisetag (no @)",
218
230
  validation: import_zod.z.string().min(1).regex(/^[a-zA-Z0-9_-]+$/),
219
- transform: (v) => v.replace(/^@+/, "").trim()
231
+ transform: (v) => v.replace(/^@+/, "").trim(),
232
+ extensionRegistration: {
233
+ providerId: "wise",
234
+ requiredPrompt: "This Wisetag is not registered yet. Verify it in the Peer extension, then refresh and retry with the same Wisetag.",
235
+ ctaLabel: "Install Peer Extension",
236
+ minExtensionVersion: "0.4.12"
237
+ }
220
238
  },
221
239
  mercadopago: {
222
240
  id: "mercadopago",
@@ -237,10 +255,18 @@ var BLUEPRINTS = {
237
255
  paypal: {
238
256
  id: "paypal",
239
257
  name: "PayPal",
240
- identifierLabel: "Email",
241
- placeholder: "email",
242
- helperText: "Email linked to PayPal account",
243
- validation: import_zod.z.string().email()
258
+ identifierLabel: "PayPal.me Username",
259
+ placeholder: "paypal.me/your-username",
260
+ helperText: "Your PayPal.me username, not your email",
261
+ validation: import_zod.z.string().min(1, "PayPal.me username is required").regex(/^[a-z0-9._-]+$/i, "Use your PayPal.me username (letters, numbers, . _ -)"),
262
+ transform: normalizePaypalMeUsername,
263
+ extensionRegistration: {
264
+ providerId: "paypal",
265
+ requiredPrompt: "This PayPal username is not registered yet. Verify it in the Peer extension, then refresh and retry with the same PayPal username.",
266
+ ctaLabel: "Install Peer Extension",
267
+ ctaSubtext: "PayPal Business accounts are not supported at this time.",
268
+ minExtensionVersion: "0.4.14"
269
+ }
244
270
  },
245
271
  monzo: {
246
272
  id: "monzo",
@@ -271,6 +297,7 @@ function buildPlatformEntry(bp) {
271
297
  placeholder: bp.placeholder,
272
298
  help: bp.helperText
273
299
  },
300
+ ...bp.extensionRegistration ? { extensionRegistration: bp.extensionRegistration } : {},
274
301
  validate(input) {
275
302
  const transformed = bp.transform ? bp.transform(input) : input;
276
303
  const result = bp.validation.safeParse(transformed);
@@ -297,6 +324,9 @@ var PLATFORMS = {
297
324
  MONZO: buildPlatformEntry(BLUEPRINTS.monzo),
298
325
  N26: buildPlatformEntry(BLUEPRINTS.n26)
299
326
  };
327
+ function getPlatformById(id) {
328
+ return Object.values(PLATFORMS).find((p) => p.id === id) ?? null;
329
+ }
300
330
  function normalizePaymentMethodLookupName(platform) {
301
331
  const normalized = platform.trim().toLowerCase();
302
332
  if (!normalized) return null;
@@ -340,34 +370,36 @@ function getPaymentMethodHashes(platform) {
340
370
  }
341
371
  return Array.from(hashes);
342
372
  }
343
- function buildDepositData(platform, identifier) {
344
- switch (platform) {
345
- case "venmo":
346
- return { venmoUsername: identifier, telegramUsername: "" };
347
- case "cashapp":
348
- return { cashtag: identifier, telegramUsername: "" };
349
- case "chime":
350
- return { chimesign: identifier.toLowerCase(), telegramUsername: "" };
351
- case "revolut":
352
- return { revolutUsername: identifier, telegramUsername: "" };
353
- case "wise":
354
- return { wisetag: identifier, telegramUsername: "" };
355
- case "mercadopago":
356
- return { cvu: identifier, telegramUsername: "" };
357
- case "zelle":
358
- return { zelleEmail: identifier, telegramUsername: "" };
359
- case "paypal":
360
- return { paypalEmail: identifier, telegramUsername: "" };
361
- case "monzo":
362
- return { monzoMeUsername: identifier, telegramUsername: "" };
363
- case "n26":
364
- return { iban: identifier, telegramUsername: "" };
365
- default:
366
- return { identifier, telegramUsername: "" };
367
- }
373
+ function buildDepositData(platform, identifier, telegramUsername = "") {
374
+ const offchainId = platform === "chime" ? identifier.toLowerCase() : identifier;
375
+ return telegramUsername ? { offchainId, telegramUsername } : { offchainId };
376
+ }
377
+ function getPeerExtensionRegistrationInfo(platform) {
378
+ const entry = getPlatformById(platform);
379
+ return entry?.extensionRegistration ?? null;
380
+ }
381
+ var EXTENSION_REGISTRATION_ERROR_PATTERNS = ["creating the maker", "create the maker"];
382
+ function isPeerExtensionRegistrationError(platform, message, statusCode) {
383
+ const info = getPeerExtensionRegistrationInfo(platform);
384
+ if (!info) return false;
385
+ if (statusCode === 400) return true;
386
+ const normalized = (message ?? "").trim();
387
+ if (!normalized) return false;
388
+ const lower = normalized.toLowerCase();
389
+ return EXTENSION_REGISTRATION_ERROR_PATTERNS.some((p) => lower.includes(p));
368
390
  }
369
391
 
370
392
  // src/errors.ts
393
+ var MakersCreateError = class extends Error {
394
+ status;
395
+ body;
396
+ constructor(message, status, body) {
397
+ super(message);
398
+ this.name = "MakersCreateError";
399
+ this.status = status;
400
+ this.body = body;
401
+ }
402
+ };
371
403
  var OfframpError = class extends Error {
372
404
  code;
373
405
  step;
@@ -1069,23 +1101,39 @@ function extractDepositIdFromLogs(logs) {
1069
1101
  }
1070
1102
  return null;
1071
1103
  }
1072
- async function registerPayeeDetails(processorName, depositData) {
1104
+ async function registerPayeeDetails(processorName, payload) {
1073
1105
  const controller = new AbortController();
1074
1106
  const timeout = setTimeout(() => controller.abort(), PAYEE_REGISTRATION_TIMEOUT_MS);
1075
1107
  try {
1076
- const res = await fetch(`${API_BASE_URL}/v1/makers/create`, {
1108
+ const res = await fetch(`${API_BASE_URL}/v2/makers/create`, {
1077
1109
  method: "POST",
1078
1110
  headers: { "Content-Type": "application/json" },
1079
- body: JSON.stringify({ processorName, depositData }),
1111
+ body: JSON.stringify({ processorName, ...payload }),
1080
1112
  signal: controller.signal
1081
1113
  });
1082
1114
  if (!res.ok) {
1083
1115
  const txt = await res.text().catch(() => "");
1084
- throw new Error(`makers/create failed (${res.status}): ${txt || res.statusText}`);
1116
+ let detail = txt || res.statusText;
1117
+ try {
1118
+ const parsed = JSON.parse(txt);
1119
+ if (typeof parsed.message === "string" && parsed.message.trim()) {
1120
+ detail = parsed.message;
1121
+ }
1122
+ } catch {
1123
+ }
1124
+ throw new MakersCreateError(
1125
+ `makers/create failed (${res.status}): ${detail}`,
1126
+ res.status,
1127
+ txt
1128
+ );
1085
1129
  }
1086
1130
  const json = await res.json();
1087
1131
  if (!json.success || !json.responseObject?.hashedOnchainId) {
1088
- throw new Error(json.message || "makers/create returned no hashedOnchainId");
1132
+ throw new MakersCreateError(
1133
+ json.message || "makers/create returned no hashedOnchainId",
1134
+ json.statusCode ?? null,
1135
+ ""
1136
+ );
1089
1137
  }
1090
1138
  return json.responseObject.hashedOnchainId;
1091
1139
  } finally {
@@ -1287,11 +1335,21 @@ async function offramp(walletClient, params, onProgress, telemetryContext) {
1287
1335
  }
1288
1336
  emitProgress({ step: "registering" });
1289
1337
  let hashedOnchainId;
1338
+ const canonicalName = platformId.startsWith("zelle") ? "zelle" : platformId;
1290
1339
  try {
1291
- const canonicalName = platformId.startsWith("zelle") ? "zelle" : platformId;
1292
- const depositData = buildDepositData(platformId, normalizedIdentifier);
1293
- hashedOnchainId = await registerPayeeDetails(canonicalName, depositData);
1340
+ const payeePayload = buildDepositData(canonicalName, normalizedIdentifier);
1341
+ hashedOnchainId = await registerPayeeDetails(canonicalName, payeePayload);
1294
1342
  } catch (err) {
1343
+ const status = err instanceof MakersCreateError ? err.status : null;
1344
+ const message = err instanceof Error ? err.message : String(err);
1345
+ if (isPeerExtensionRegistrationError(canonicalName, message, status)) {
1346
+ throw new OfframpError(
1347
+ `${platform.name} maker is not yet registered in the Peer extension. Verify this handle in the extension, then retry.`,
1348
+ "EXTENSION_REGISTRATION_REQUIRED",
1349
+ "registering",
1350
+ err
1351
+ );
1352
+ }
1295
1353
  throw new OfframpError(
1296
1354
  "Payee registration failed",
1297
1355
  "REGISTRATION_FAILED",
@@ -1685,8 +1743,129 @@ function useOfframp(defaultOptions = {}) {
1685
1743
  reset
1686
1744
  };
1687
1745
  }
1746
+
1747
+ // src/hooks/usePeerExtensionRegistration.ts
1748
+ var import_react2 = require("react");
1749
+
1750
+ // src/extension.ts
1751
+ var import_sdk7 = require("@zkp2p/sdk");
1752
+
1753
+ // src/hooks/usePeerExtensionRegistration.ts
1754
+ function usePeerExtensionRegistration(platform) {
1755
+ const info = platform ? getPeerExtensionRegistrationInfo(platform.id) : null;
1756
+ const [phase, setPhase] = (0, import_react2.useState)(
1757
+ info ? "checking" : "unsupported"
1758
+ );
1759
+ const [busy, setBusy] = (0, import_react2.useState)(false);
1760
+ const [error, setError] = (0, import_react2.useState)(null);
1761
+ const mountedRef = (0, import_react2.useRef)(true);
1762
+ const providerId = info?.providerId ?? null;
1763
+ const refresh = (0, import_react2.useCallback)(async () => {
1764
+ if (!providerId) {
1765
+ setPhase("unsupported");
1766
+ return;
1767
+ }
1768
+ try {
1769
+ const state = await import_sdk7.peerExtensionSdk.getState();
1770
+ if (!mountedRef.current) return;
1771
+ setPhase(mapSdkState(state));
1772
+ } catch {
1773
+ if (!mountedRef.current) return;
1774
+ setPhase("needs_install");
1775
+ }
1776
+ }, [providerId]);
1777
+ (0, import_react2.useEffect)(() => {
1778
+ mountedRef.current = true;
1779
+ setError(null);
1780
+ setBusy(false);
1781
+ if (!providerId) {
1782
+ setPhase("unsupported");
1783
+ } else {
1784
+ setPhase("checking");
1785
+ refresh();
1786
+ }
1787
+ return () => {
1788
+ mountedRef.current = false;
1789
+ };
1790
+ }, [providerId, refresh]);
1791
+ const installExtension = (0, import_react2.useCallback)(() => {
1792
+ setError(null);
1793
+ try {
1794
+ import_sdk7.peerExtensionSdk.openInstallPage();
1795
+ } catch {
1796
+ if (typeof window !== "undefined") {
1797
+ window.open(import_sdk7.PEER_EXTENSION_CHROME_URL, "_blank", "noopener,noreferrer");
1798
+ }
1799
+ }
1800
+ }, []);
1801
+ const connectExtension = (0, import_react2.useCallback)(async () => {
1802
+ if (!providerId) return false;
1803
+ setError(null);
1804
+ setBusy(true);
1805
+ try {
1806
+ const approved = await import_sdk7.peerExtensionSdk.requestConnection();
1807
+ if (!mountedRef.current) return approved;
1808
+ if (approved) {
1809
+ setPhase("ready");
1810
+ import_sdk7.peerExtensionSdk.openSidebar(`/verify/${providerId}`);
1811
+ } else {
1812
+ setError("Connection was not approved. Try again once you've approved Peer.");
1813
+ }
1814
+ return approved;
1815
+ } catch (err) {
1816
+ if (!mountedRef.current) return false;
1817
+ setError(
1818
+ err instanceof Error ? err.message : "Couldn't request a Peer extension connection. Make sure Peer is installed and enabled."
1819
+ );
1820
+ refresh();
1821
+ return false;
1822
+ } finally {
1823
+ if (mountedRef.current) setBusy(false);
1824
+ }
1825
+ }, [providerId, refresh]);
1826
+ const openVerifySidebar = (0, import_react2.useCallback)(async () => {
1827
+ if (!providerId) return;
1828
+ setError(null);
1829
+ const state = await import_sdk7.peerExtensionSdk.getState().catch(() => "needs_install");
1830
+ if (!mountedRef.current) return;
1831
+ const nextPhase = mapSdkState(state);
1832
+ setPhase(nextPhase);
1833
+ if (nextPhase === "needs_install") {
1834
+ installExtension();
1835
+ return;
1836
+ }
1837
+ if (nextPhase === "needs_connection") {
1838
+ await connectExtension();
1839
+ return;
1840
+ }
1841
+ try {
1842
+ import_sdk7.peerExtensionSdk.openSidebar(`/verify/${providerId}`);
1843
+ } catch (err) {
1844
+ setError(
1845
+ err instanceof Error ? err.message : "Couldn't open the Peer extension. Make sure it's enabled."
1846
+ );
1847
+ refresh();
1848
+ }
1849
+ }, [connectExtension, installExtension, providerId, refresh]);
1850
+ return {
1851
+ phase,
1852
+ info,
1853
+ busy,
1854
+ error,
1855
+ refresh,
1856
+ installExtension,
1857
+ connectExtension,
1858
+ openVerifySidebar
1859
+ };
1860
+ }
1861
+ function mapSdkState(state) {
1862
+ if (state === "needs_install") return "needs_install";
1863
+ if (state === "needs_connection") return "needs_connection";
1864
+ return "ready";
1865
+ }
1688
1866
  // Annotate the CommonJS export names for ESM import in node:
1689
1867
  0 && (module.exports = {
1690
- useOfframp
1868
+ useOfframp,
1869
+ usePeerExtensionRegistration
1691
1870
  });
1692
1871
  //# sourceMappingURL=react.cjs.map