@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/README.md +65 -10
- package/dist/buttons.d.ts.map +1 -1
- package/dist/modal/config.d.ts +8 -0
- package/dist/modal/config.d.ts.map +1 -1
- package/dist/modal/index.js +1 -1
- package/dist/modal/modal.d.ts +23 -3
- package/dist/modal/modal.d.ts.map +1 -1
- package/dist/{modal-CvQ7qr5d.js → modal-BiPk8xwF.js} +63 -33
- package/dist/pybara-js.iife.js +13 -3
- package/dist/pybara-js.js +101 -92
- package/package.json +1 -1
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
|
|
4
|
-
var
|
|
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
|
|
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
|
|
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
|
|
21
|
-
let
|
|
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([
|
|
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[
|
|
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
|
-
} :
|
|
36
|
+
} : o(d.version, "1-0") ? {
|
|
37
37
|
show: !0,
|
|
38
|
-
recurring: f[
|
|
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
|
|
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
|
|
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
|
|
62
|
+
function d(e, t) {
|
|
63
63
|
return e?.shape === "sharp" ? "0" : e?.shape === "rect" ? "4px" : `${t / 2}px`;
|
|
64
64
|
}
|
|
65
|
-
function
|
|
65
|
+
function f(e) {
|
|
66
66
|
let t = typeof e == "string" ? document.querySelector(e) : e;
|
|
67
|
-
if (!t) throw new
|
|
67
|
+
if (!t) throw new l("INVALID_CONFIG", `buttons().render(): no element matches ${JSON.stringify(e)}`);
|
|
68
68
|
return t;
|
|
69
69
|
}
|
|
70
|
-
function
|
|
71
|
-
if (typeof t?.createPayment != "function") throw new
|
|
72
|
-
let n = new URL(e.walletUrl).origin,
|
|
73
|
-
async function
|
|
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
|
|
87
|
-
let
|
|
88
|
-
|
|
89
|
-
let
|
|
90
|
-
|
|
91
|
-
let
|
|
92
|
-
|
|
93
|
-
let
|
|
94
|
-
|
|
95
|
-
let
|
|
96
|
-
|
|
97
|
-
},
|
|
98
|
-
|
|
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
|
-
}),
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
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
|
|
113
|
-
if (e.origin !== n || e.source !==
|
|
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" && (
|
|
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:
|
|
119
|
-
}))) : t?.type === "pybara_button_click" &&
|
|
127
|
+
status: _.status
|
|
128
|
+
}))) : t?.type === "pybara_button_click" && o();
|
|
120
129
|
};
|
|
121
|
-
window.addEventListener("message",
|
|
122
|
-
let
|
|
123
|
-
|
|
124
|
-
window.removeEventListener("message",
|
|
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:
|
|
137
|
+
render: s,
|
|
129
138
|
destroy() {
|
|
130
|
-
for (let e of
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
190
|
-
let t =
|
|
191
|
-
if (t === null) throw new
|
|
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
|
|
194
|
-
if (!/^[A-Z]{3}$/.test(n)) throw new
|
|
195
|
-
if (e.durationMonths != null && !e.frequency) throw new
|
|
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
|
|
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
|
|
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:
|
|
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,
|
|
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
|
|
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,
|
|
256
|
-
this.modal = new
|
|
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) =>
|
|
270
|
+
onAvailability: (e) => r.emitAvailability(e),
|
|
262
271
|
onSuccess: (e) => {
|
|
263
|
-
|
|
264
|
-
let t =
|
|
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:
|
|
277
|
+
recurring: i,
|
|
269
278
|
frequency: t?.frequency,
|
|
270
|
-
durationMonths:
|
|
271
|
-
isUnlimited:
|
|
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
|
-
|
|
279
|
-
let t =
|
|
280
|
-
|
|
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
|
-
|
|
284
|
-
let e =
|
|
285
|
-
|
|
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
|
|
350
|
+
function _(e) {
|
|
342
351
|
let t = typeof e == "number" && Number.isFinite(e) ? String(e) : e;
|
|
343
|
-
return typeof t != "string" || !
|
|
352
|
+
return typeof t != "string" || !m.test(t) || !/[1-9]/.test(t) ? null : t;
|
|
344
353
|
}
|
|
345
|
-
function
|
|
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
|
|
357
|
-
if (!e.recipientPrincipal) throw new
|
|
358
|
-
if (!e.siteUrl) throw new
|
|
359
|
-
let t =
|
|
360
|
-
if (!t) throw new
|
|
361
|
-
if (!e.siteName) throw new
|
|
362
|
-
if (e.currency != null && !/^[A-Z]{3}$/.test(e.currency)) throw new
|
|
363
|
-
if (e.platform != null && !
|
|
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
|
|
380
|
+
function b() {
|
|
372
381
|
let e = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
|
|
373
382
|
return btoa(String.fromCharCode(...e));
|
|
374
383
|
}
|
|
375
|
-
function
|
|
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
|
|
381
|
-
return new
|
|
389
|
+
function S(e) {
|
|
390
|
+
return new g(e);
|
|
382
391
|
}
|
|
383
|
-
var
|
|
392
|
+
var C = { checkout: S };
|
|
384
393
|
//#endregion
|
|
385
|
-
export {
|
|
394
|
+
export { C as Pybara, g as PybaraCheckout, l as PybaraError, S as checkout };
|
package/package.json
CHANGED