@pybara/pybara-js 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/pybara-js.js CHANGED
@@ -1,26 +1,26 @@
1
1
  /* Pybara.js - pybara.com */
2
2
  import { n as e, r as t, t as n } from "./admin-B1pVP25-.js";
3
- import { t as r } from "./modal-CvQ7qr5d.js";
4
- var i = {
3
+ import { r, t as i } from "./modal-BiPk8xwF.js";
4
+ var a = {
5
5
  widget: "donate-widget",
6
6
  recurring: "donate-widget-recurring"
7
7
  };
8
- function a(e, t) {
8
+ function o(e, t) {
9
9
  let n = (e) => {
10
10
  let t = /^(\d+)-(\d+)$/.exec(e);
11
11
  return t ? [Number(t[1]), Number(t[2])] : null;
12
12
  }, r = n(e), i = n(t);
13
13
  return !r || !i ? !1 : r[0] > i[0] || r[0] === i[0] && r[1] >= i[1];
14
14
  }
15
- async function o(e) {
15
+ async function s(e) {
16
16
  let t = await fetch(e);
17
17
  if (!t.ok) throw Error(`HTTP ${t.status} from ${e}`);
18
18
  return await t.json();
19
19
  }
20
- async function s(t, n, r) {
21
- let s = e[t], c = `https://${s.admin_core}.raw.icp0.io/widget-config`, l = `https://${s.admin_regs}.raw.icp0.io/widget-terms?site_url=${encodeURIComponent(n)}&principal=${encodeURIComponent(r)}`, u, d;
20
+ async function c(t, n, r) {
21
+ let i = e[t], c = `https://${i.admin_core}.raw.icp0.io/widget-config`, l = `https://${i.admin_regs}.raw.icp0.io/widget-terms?site_url=${encodeURIComponent(n)}&principal=${encodeURIComponent(r)}`, u, d;
22
22
  try {
23
- [u, d] = await Promise.all([o(c), o(l)]);
23
+ [u, d] = await Promise.all([s(c), s(l)]);
24
24
  } catch (e) {
25
25
  return {
26
26
  show: !1,
@@ -29,13 +29,13 @@ async function s(t, n, r) {
29
29
  };
30
30
  }
31
31
  let f = u.kill_switch?.plugins ?? {};
32
- return f[i.widget]?.enabled === !0 ? !d.signed || !d.version ? {
32
+ return f[a.widget]?.enabled === !0 ? !d.signed || !d.version ? {
33
33
  show: !1,
34
34
  cause: "terms",
35
35
  reason: `${n} has not accepted the widget's terms in Pybara Wallet (Manage › Sites › Add a site without a plugin)`
36
- } : a(d.version, "1-0") ? {
36
+ } : o(d.version, "1-0") ? {
37
37
  show: !0,
38
- recurring: f[i.recurring]?.enabled === !0
38
+ recurring: f[a.recurring]?.enabled === !0
39
39
  } : {
40
40
  show: !1,
41
41
  cause: "terms",
@@ -48,29 +48,29 @@ async function s(t, n, r) {
48
48
  }
49
49
  //#endregion
50
50
  //#region src/types.ts
51
- var c = class extends Error {
51
+ var l = class extends Error {
52
52
  constructor(e, t) {
53
53
  super(t), this.name = "PybaraError", this.code = e;
54
54
  }
55
55
  };
56
56
  //#endregion
57
57
  //#region src/buttons.ts
58
- function l(e) {
58
+ function u(e) {
59
59
  let t = typeof e?.height == "number" && Number.isFinite(e.height) ? Math.round(e.height) : 45;
60
60
  return Math.min(55, Math.max(25, t));
61
61
  }
62
- function u(e, t) {
62
+ function d(e, t) {
63
63
  return e?.shape === "sharp" ? "0" : e?.shape === "rect" ? "4px" : `${t / 2}px`;
64
64
  }
65
- function d(e) {
65
+ function f(e) {
66
66
  let t = typeof e == "string" ? document.querySelector(e) : e;
67
- if (!t) throw new c("INVALID_CONFIG", `buttons().render(): no element matches ${JSON.stringify(e)}`);
67
+ if (!t) throw new l("INVALID_CONFIG", `buttons().render(): no element matches ${JSON.stringify(e)}`);
68
68
  return t;
69
69
  }
70
- function f(e, t) {
71
- if (typeof t?.createPayment != "function") throw new c("INVALID_CONFIG", "buttons(): \"createPayment\" is required, a function returning the payment from the form, e.g. () => ({ amount: form.amount.value, currency: \"EUR\" })");
72
- let n = new URL(e.walletUrl).origin, r = [], i = null;
73
- async function a() {
70
+ function p(e, t) {
71
+ if (typeof t?.createPayment != "function") throw new l("INVALID_CONFIG", "buttons(): \"createPayment\" is required, a function returning the payment from the form, e.g. () => ({ amount: form.amount.value, currency: \"EUR\" })");
72
+ let n = new URL(e.walletUrl).origin, i = [], a = null;
73
+ async function o() {
74
74
  try {
75
75
  let n = await t.createPayment();
76
76
  await e.open({
@@ -83,62 +83,71 @@ function f(e, t) {
83
83
  t.onError?.(e instanceof Error ? e : Error(String(e)));
84
84
  }
85
85
  }
86
- function o(o) {
87
- let s = d(o), c = l(t.style), f = document.createElement("div");
88
- f.style.cssText = `position:relative;width:100%;height:${c}px;`;
89
- let p = document.createElement("div");
90
- p.setAttribute("aria-hidden", "true"), p.style.cssText = `position:absolute;inset:0;border-radius:${u(t.style, c)};background:rgba(128,128,128,0.16);`;
91
- let m = document.createElement("iframe");
92
- m.src = `${n}/button`, m.title = "Pybara", m.style.cssText = "position:absolute;inset:0;width:100%;height:100%;border:0;opacity:0;color-scheme:normal;background:transparent;", f.append(p, m), s.appendChild(f);
93
- let h = !1, g = null, _ = {};
94
- i ??= _;
95
- let v = (e) => {
96
- m.contentWindow?.postMessage(e, n);
97
- }, y = (e) => {
98
- g = e, h && v({
86
+ function s(s) {
87
+ let c = f(s), l = u(t.style), p = document.createElement("div");
88
+ p.style.cssText = `position:relative;width:100%;height:${l}px;`;
89
+ let m = document.createElement("div");
90
+ m.setAttribute("aria-hidden", "true"), m.style.cssText = `position:absolute;inset:0;border-radius:${d(t.style, l)};background:rgba(128,128,128,0.16);`;
91
+ let h = document.createElement("iframe");
92
+ h.src = `${n}/button`, h.title = "Pybara", h.style.cssText = "position:absolute;inset:0;width:100%;height:100%;border:0;opacity:0;color-scheme:normal;background:transparent;", p.append(m, h), c.appendChild(p);
93
+ let g = !1, _ = null, v = {};
94
+ a ??= v;
95
+ let y = (e) => {
96
+ h.contentWindow?.postMessage(e, n);
97
+ }, b = (e) => {
98
+ _ = e, g && y({
99
99
  type: "pybara_button_availability",
100
100
  v: 1,
101
101
  status: e.status
102
- }), i ??= _, i === _ && t.onStateChange?.(e);
103
- };
104
- m.addEventListener("load", () => {
105
- v({
102
+ }), a ??= v, a === v && t.onStateChange?.(e);
103
+ }, x = setTimeout(() => {
104
+ if (g) return;
105
+ m.remove(), t.hideWhenUnavailable === !0 && (p.style.height = "0px");
106
+ let e = `Pybara: the button (${n}/button) did not load within ${r / 1e3} seconds; pybara.io may be unreachable from this browser.`;
107
+ console.warn(e), a ??= v, a === v && t.onStateChange?.({
108
+ status: "unavailable",
109
+ reason: "BUTTON_UNAVAILABLE",
110
+ detail: e
111
+ });
112
+ }, r);
113
+ h.addEventListener("load", () => {
114
+ y({
106
115
  type: "pybara_button_init",
107
116
  v: 1,
108
117
  style: t.style ?? {},
109
118
  hideWhenUnavailable: t.hideWhenUnavailable === !0
110
119
  });
111
120
  }, { once: !0 });
112
- let b = (e) => {
113
- if (e.origin !== n || e.source !== m.contentWindow) return;
121
+ let S = (e) => {
122
+ if (e.origin !== n || e.source !== h.contentWindow) return;
114
123
  let t = e.data;
115
- t?.type === "pybara_button_ready" || t?.type === "pybara_button_resize" ? (typeof t.height == "number" && (f.style.height = `${t.height}px`), h || (h = !0, m.style.opacity = "1", p.remove(), g && v({
124
+ t?.type === "pybara_button_ready" || t?.type === "pybara_button_resize" ? (typeof t.height == "number" && (p.style.height = `${t.height}px`), g || (g = !0, clearTimeout(x), h.style.opacity = "1", m.remove(), _ && y({
116
125
  type: "pybara_button_availability",
117
126
  v: 1,
118
- status: g.status
119
- }))) : t?.type === "pybara_button_click" && a();
127
+ status: _.status
128
+ }))) : t?.type === "pybara_button_click" && o();
120
129
  };
121
- window.addEventListener("message", b);
122
- let x = e.subscribeAvailability(y);
123
- r.push(() => {
124
- window.removeEventListener("message", b), x(), i === _ && (i = null), f.remove();
130
+ window.addEventListener("message", S);
131
+ let C = e.subscribeAvailability(b);
132
+ i.push(() => {
133
+ clearTimeout(x), window.removeEventListener("message", S), C(), a === v && (a = null), p.remove();
125
134
  });
126
135
  }
127
136
  return {
128
- render: o,
137
+ render: s,
129
138
  destroy() {
130
- for (let e of r.splice(0)) e();
139
+ for (let e of i.splice(0)) e();
131
140
  }
132
141
  };
133
142
  }
134
143
  //#endregion
135
144
  //#region src/checkout.ts
136
- var p = /^(0|[1-9]\d*)(\.\d+)?$/, m = /^[a-z0-9-]{1,64}$/, h = class {
145
+ var m = /^(0|[1-9]\d*)(\.\d+)?$/, h = /^[a-z0-9-]{1,64}$/, g = class {
137
146
  constructor(e) {
138
- this.adminClient = null, this.modal = null, this.gateOutcome = null, this.isOpen = !1, this.completedPayment = !1, this.activePayment = null, this.lastPrecheck = {}, this.availabilityListeners = /* @__PURE__ */ new Set(), this.latestAvailability = null, this.config = v(e), this.config.onAvailability && this.availabilityListeners.add(this.config.onAvailability), this.ready = this.init(), this.config.onAvailability && this.precheck();
147
+ this.adminClient = null, this.modal = null, this.gateOutcome = null, this.isOpen = !1, this.completedPayment = !1, this.activePayment = null, this.lastPrecheck = {}, this.availabilityListeners = /* @__PURE__ */ new Set(), this.latestAvailability = null, this.config = y(e), this.config.onAvailability && this.availabilityListeners.add(this.config.onAvailability), this.ready = this.init(), this.config.onAvailability && this.precheck();
139
148
  }
140
149
  buttons(e) {
141
- return f({
150
+ return p({
142
151
  walletUrl: t[this.config.staging ? "staging" : "prod"],
143
152
  open: (e) => this.open(e),
144
153
  subscribeAvailability: (e) => (this.availabilityListeners.add(e), this.latestAvailability ? e(this.latestAvailability) : !this.config.onAvailability && this.availabilityListeners.size === 1 && this.precheck(this.lastPrecheck), () => {
@@ -186,18 +195,18 @@ var p = /^(0|[1-9]\d*)(\.\d+)?$/, m = /^[a-z0-9-]{1,64}$/, h = class {
186
195
  return this.gateOutcome;
187
196
  }
188
197
  async open(e) {
189
- if (await this.ready, this.gateOutcome && !this.gateOutcome.show) throw new c("GATE_REFUSED", this.gateOutcome.reason ?? "This site cannot accept Pybara payments yet.");
190
- let t = g(e.amount);
191
- if (t === null) throw new c("INVALID_CONFIG", `open(): "amount" must be a decimal string in the currency's major units, e.g. "12.34", or a positive number — got ${JSON.stringify(e.amount)}`);
198
+ if (await this.ready, this.gateOutcome && !this.gateOutcome.show) throw new l("GATE_REFUSED", this.gateOutcome.reason ?? "This site cannot accept Pybara payments yet.");
199
+ let t = _(e.amount);
200
+ if (t === null) throw new l("INVALID_CONFIG", `open(): "amount" must be a decimal string in the currency's major units, e.g. "12.34", or a positive number — got ${JSON.stringify(e.amount)}`);
192
201
  let n = e.currency ?? this.config.currency;
193
- if (!n) throw new c("INVALID_CONFIG", "open(): \"currency\" is required — pass it to open(), or set it once in Pybara.checkout()");
194
- if (!/^[A-Z]{3}$/.test(n)) throw new c("INVALID_CONFIG", `open(): "currency" must be an uppercase ISO 4217 code, e.g. "EUR" — got ${JSON.stringify(n)}`);
195
- if (e.durationMonths != null && !e.frequency) throw new c("INVALID_CONFIG", "open(): \"durationMonths\" needs a \"frequency\"");
202
+ if (!n) throw new l("INVALID_CONFIG", "open(): \"currency\" is required — pass it to open(), or set it once in Pybara.checkout()");
203
+ if (!/^[A-Z]{3}$/.test(n)) throw new l("INVALID_CONFIG", `open(): "currency" must be an uppercase ISO 4217 code, e.g. "EUR" — got ${JSON.stringify(n)}`);
204
+ if (e.durationMonths != null && !e.frequency) throw new l("INVALID_CONFIG", "open(): \"durationMonths\" needs a \"frequency\"");
196
205
  let r = e.frequency ? {
197
206
  frequency: e.frequency,
198
207
  ...e.durationMonths == null ? {} : { durationMonths: e.durationMonths }
199
208
  } : void 0;
200
- if (r && this.gateOutcome && this.gateOutcome.show && !this.gateOutcome.recurring) throw new c("GATE_REFUSED", "Recurring payments are temporarily unavailable.");
209
+ if (r && this.gateOutcome && this.gateOutcome.show && !this.gateOutcome.recurring) throw new l("GATE_REFUSED", "Recurring payments are temporarily unavailable.");
201
210
  if (this.isOpen) return;
202
211
  this.isOpen = !0;
203
212
  let i = !1;
@@ -208,7 +217,7 @@ var p = /^(0|[1-9]\d*)(\.\d+)?$/, m = /^[a-z0-9-]{1,64}$/, h = class {
208
217
  }
209
218
  this.modal || this.initCheckoutModal();
210
219
  let a = this.modal;
211
- if (!a) throw this.isOpen = !1, new c("CHECKOUT_FAILED", "The checkout modal could not be initialised.");
220
+ if (!a) throw this.isOpen = !1, new l("CHECKOUT_FAILED", "The checkout modal could not be initialised.");
212
221
  if (i) this.isOpen = !1, a.renderTerminalState("This recipient is currently unable to accept donations."), this.initCheckoutModal();
213
222
  else {
214
223
  this.activePayment = e;
@@ -216,14 +225,14 @@ var p = /^(0|[1-9]\d*)(\.\d+)?$/, m = /^[a-z0-9-]{1,64}$/, h = class {
216
225
  a.show({
217
226
  modalData: {
218
227
  beneficiary: this.config.recipientPrincipal,
219
- salt: y(),
228
+ salt: b(),
220
229
  reference: this.config.siteName
221
230
  },
222
231
  recurring: r,
223
232
  checkout: this.checkoutFor(e, t, n)
224
233
  });
225
234
  } catch (e) {
226
- throw this.isOpen = !1, this.activePayment = null, b(e);
235
+ throw this.isOpen = !1, this.activePayment = null, x(e);
227
236
  }
228
237
  }
229
238
  }
@@ -247,42 +256,42 @@ var p = /^(0|[1-9]\d*)(\.\d+)?$/, m = /^[a-z0-9-]{1,64}$/, h = class {
247
256
  r && console.error("🧩 pybara-js: admin client init failed:", e);
248
257
  }
249
258
  })(), o = (async () => {
250
- this.config.pluginVersion || (this.gateOutcome = await s(t, this.config.siteUrl, this.config.recipientPrincipal), !this.gateOutcome.show && r && console.warn("🧩 pybara-js: gate refused —", this.gateOutcome.reason));
259
+ this.config.pluginVersion || (this.gateOutcome = await c(t, this.config.siteUrl, this.config.recipientPrincipal), !this.gateOutcome.show && r && console.warn("🧩 pybara-js: gate refused —", this.gateOutcome.reason));
251
260
  })();
252
261
  await Promise.all([a, o]);
253
262
  }
254
263
  initCheckoutModal() {
255
- let e = this.config.staging ? "staging" : "prod", n = this.config, i = this;
256
- this.modal = new r({
264
+ let e = this.config.staging ? "staging" : "prod", n = this.config, r = this;
265
+ this.modal = new i({
257
266
  walletUrl: t[e],
258
267
  context: "donation",
259
268
  thankYouMessage: n.thankYouMessage,
260
269
  locale: n.locale,
261
- onAvailability: (e) => i.emitAvailability(e),
270
+ onAvailability: (e) => r.emitAvailability(e),
262
271
  onSuccess: (e) => {
263
- i.completedPayment = !0;
264
- let t = i.activePayment, r = t?.frequency != null, a = {
272
+ r.completedPayment = !0;
273
+ let t = r.activePayment, i = t?.frequency != null, a = {
265
274
  blockIndex: e.blockIndex,
266
275
  reference: e.reference,
267
276
  token: e.token,
268
- recurring: r,
277
+ recurring: i,
269
278
  frequency: t?.frequency,
270
- durationMonths: r ? t?.durationMonths ?? void 0 : void 0,
271
- isUnlimited: r && t?.durationMonths == null,
279
+ durationMonths: i ? t?.durationMonths ?? void 0 : void 0,
280
+ isUnlimited: i && t?.durationMonths == null,
272
281
  payerPrincipal: e.payerPrincipal,
273
282
  recipientPrincipal: n.recipientPrincipal
274
283
  };
275
284
  t?.onSuccess?.(a);
276
285
  },
277
286
  onError: (e) => {
278
- i.isOpen = !1;
279
- let t = i.activePayment;
280
- i.activePayment = null, t?.onError?.(b(e)), i.modal = null, i.initCheckoutModal();
287
+ r.isOpen = !1;
288
+ let t = r.activePayment;
289
+ r.activePayment = null, t?.onError?.(x(e)), r.modal = null, r.initCheckoutModal();
281
290
  },
282
291
  onClose: () => {
283
- i.isOpen = !1;
284
- let e = i.activePayment;
285
- i.activePayment = null, e?.onClose?.(), i.completedPayment && n.thankYouRedirectUrl ? window.location.href = n.thankYouRedirectUrl : (i.completedPayment = !1, i.modal = null, i.initCheckoutModal());
292
+ r.isOpen = !1;
293
+ let e = r.activePayment;
294
+ r.activePayment = null, e?.onClose?.(), r.completedPayment && n.thankYouRedirectUrl ? window.location.href = n.thankYouRedirectUrl : (r.completedPayment = !1, r.modal = null, r.initCheckoutModal());
286
295
  }
287
296
  }), this.availabilityListeners.size > 0 && this.modal && Object.keys(this.lastPrecheck).length > 0 && this.sendPrecheck();
288
297
  }
@@ -338,11 +347,11 @@ var p = /^(0|[1-9]\d*)(\.\d+)?$/, m = /^[a-z0-9-]{1,64}$/, h = class {
338
347
  n.rel = "preconnect", n.href = new URL(t[e]).origin, n.crossOrigin = "anonymous", document.head.appendChild(n);
339
348
  }
340
349
  };
341
- function g(e) {
350
+ function _(e) {
342
351
  let t = typeof e == "number" && Number.isFinite(e) ? String(e) : e;
343
- return typeof t != "string" || !p.test(t) || !/[1-9]/.test(t) ? null : t;
352
+ return typeof t != "string" || !m.test(t) || !/[1-9]/.test(t) ? null : t;
344
353
  }
345
- function _(e) {
354
+ function v(e) {
346
355
  let t = e.trim();
347
356
  if (!t) return null;
348
357
  let n;
@@ -353,14 +362,14 @@ function _(e) {
353
362
  }
354
363
  return n.protocol !== "https:" && n.protocol !== "http:" ? null : n.origin + n.pathname.replace(/\/+$/, "");
355
364
  }
356
- function v(e) {
357
- if (!e.recipientPrincipal) throw new c("INVALID_CONFIG", "Pybara.checkout: \"recipientPrincipal\" is required");
358
- if (!e.siteUrl) throw new c("INVALID_CONFIG", "Pybara.checkout: \"siteUrl\" is required");
359
- let t = _(e.siteUrl);
360
- if (!t) throw new c("INVALID_CONFIG", `Pybara.checkout: "siteUrl" is not a valid http(s) URL: ${e.siteUrl}`);
361
- if (!e.siteName) throw new c("INVALID_CONFIG", "Pybara.checkout: \"siteName\" is required");
362
- if (e.currency != null && !/^[A-Z]{3}$/.test(e.currency)) throw new c("INVALID_CONFIG", `Pybara.checkout: "currency" must be an uppercase ISO 4217 code, e.g. "EUR" — got ${JSON.stringify(e.currency)}`);
363
- if (e.platform != null && !m.test(e.platform)) throw new c("INVALID_CONFIG", "Pybara.checkout: \"platform\" must be a lowercase slug (a-z, 0-9, -), at most 64 characters");
365
+ function y(e) {
366
+ if (!e.recipientPrincipal) throw new l("INVALID_CONFIG", "Pybara.checkout: \"recipientPrincipal\" is required");
367
+ if (!e.siteUrl) throw new l("INVALID_CONFIG", "Pybara.checkout: \"siteUrl\" is required");
368
+ let t = v(e.siteUrl);
369
+ if (!t) throw new l("INVALID_CONFIG", `Pybara.checkout: "siteUrl" is not a valid http(s) URL: ${e.siteUrl}`);
370
+ if (!e.siteName) throw new l("INVALID_CONFIG", "Pybara.checkout: \"siteName\" is required");
371
+ if (e.currency != null && !/^[A-Z]{3}$/.test(e.currency)) throw new l("INVALID_CONFIG", `Pybara.checkout: "currency" must be an uppercase ISO 4217 code, e.g. "EUR" — got ${JSON.stringify(e.currency)}`);
372
+ if (e.platform != null && !h.test(e.platform)) throw new l("INVALID_CONFIG", "Pybara.checkout: \"platform\" must be a lowercase slug (a-z, 0-9, -), at most 64 characters");
364
373
  return {
365
374
  ...e,
366
375
  siteUrl: t,
@@ -368,18 +377,18 @@ function v(e) {
368
377
  debug: e.debug ?? !1
369
378
  };
370
379
  }
371
- function y() {
380
+ function b() {
372
381
  let e = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
373
382
  return btoa(String.fromCharCode(...e));
374
383
  }
375
- function b(e) {
384
+ function x(e) {
376
385
  return e instanceof Error ? e : Error(String(e));
377
386
  }
378
387
  //#endregion
379
388
  //#region src/index.ts
380
- function x(e) {
381
- return new h(e);
389
+ function S(e) {
390
+ return new g(e);
382
391
  }
383
- var S = { checkout: x };
392
+ var C = { checkout: S };
384
393
  //#endregion
385
- export { S as Pybara, h as PybaraCheckout, c as PybaraError, x as checkout };
394
+ export { C as Pybara, g as PybaraCheckout, l as PybaraError, S as checkout };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pybara/pybara-js",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Accept crypto payments and donations with Pybara on any page — a callable checkout, in the stripe-js / paypal-js convention.",
5
5
  "keywords": [
6
6
  "pybara",