@pybara/pybara-js 0.1.0 → 0.2.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
@@ -198,62 +198,62 @@ var y = class {
198
198
  ], C = .5, w = {
199
199
  widget: "donate-widget",
200
200
  recurring: "donate-widget-recurring"
201
- }, T = (e) => {
202
- if (!e || !e.includes("-")) return !0;
203
- let [t = 0, n = 0] = e.split("-").map(Number), [r = 0, i = 0] = "1-0".split("-").map(Number);
204
- return t < r || t === r && n < i;
205
201
  };
206
- async function E(t, n, r) {
207
- let i = `https://${e[t].admin_core}.raw.ic0.app`, a = { "Content-Type": "application/json" }, o = null;
202
+ function T(e, t) {
203
+ let n = (e) => {
204
+ let t = /^(\d+)-(\d+)$/.exec(e);
205
+ return t ? [Number(t[1]), Number(t[2])] : null;
206
+ }, r = n(e), i = n(t);
207
+ return !r || !i ? !1 : r[0] > i[0] || r[0] === i[0] && r[1] >= i[1];
208
+ }
209
+ async function E(e) {
210
+ let t = await fetch(e);
211
+ if (!t.ok) throw Error(`HTTP ${t.status} from ${e}`);
212
+ return await t.json();
213
+ }
214
+ async function D(t, n, r) {
215
+ let i = e[t], a = `https://${i.admin_core}.raw.icp0.io/widget-config`, o = `https://${i.admin_regs}.raw.icp0.io/widget-terms?site_url=${encodeURIComponent(n)}&principal=${encodeURIComponent(r)}`, s, c;
208
216
  try {
209
- let [e, t] = await Promise.all([fetch(`${i}/api/widget-terms?site_url=${encodeURIComponent(n)}&principal=${encodeURIComponent(r)}`, { headers: a }), fetch(`${i}/api/kill-switches`, { headers: a })]);
210
- if (t.ok && (o = (await t.json()).switches?.find((e) => (e.key === w.widget || e.key === w.recurring) && e.enabled === !1) ?? null, o)) return {
211
- show: !1,
212
- reason: `This integration is temporarily unavailable (${o.key})`
213
- };
214
- if (!e.ok) return {
215
- show: !1,
216
- reason: `Site not verified (${e.status})`
217
- };
218
- let s = await e.json();
219
- if (s.terms?.signed !== !0 || T(s.terms?.version)) {
220
- let e = s.terms?.superseded_version;
221
- return {
222
- show: !1,
223
- reason: e ? `Widget terms v${e} now apply — accept them in Pybara Wallet (Manage › Sites)` : "This site has not accepted the widget’s terms in Pybara Wallet (Manage › Sites)"
224
- };
225
- }
217
+ [s, c] = await Promise.all([E(a), E(o)]);
218
+ } catch (e) {
226
219
  return {
227
- show: !0,
228
- reason: null
229
- };
230
- } catch {
231
- return o ? {
232
220
  show: !1,
233
- reason: `This integration is temporarily unavailable (${o.key})`
234
- } : {
235
- show: !0,
236
- reason: null
221
+ reason: `could not read the widget's configuration (${e instanceof Error ? e.message : String(e)})`
237
222
  };
238
223
  }
224
+ let l = s.kill_switch?.plugins ?? {};
225
+ return l[w.widget]?.enabled === !0 ? !c.signed || !c.version ? {
226
+ show: !1,
227
+ reason: `${n} has not accepted the widget's terms in Pybara Wallet (Manage › Sites › Add a site without a plugin)`
228
+ } : T(c.version, "1-0") ? {
229
+ show: !0,
230
+ recurring: l[w.recurring]?.enabled === !0
231
+ } : {
232
+ show: !1,
233
+ reason: `this widget version requires terms 1-0, and ${n} accepted ${c.version}: accept the new terms in Pybara Wallet (Manage › Sites)`
234
+ } : {
235
+ show: !1,
236
+ reason: "the widget is switched off by Pybara for now"
237
+ };
239
238
  }
240
239
  //#endregion
241
240
  //#region src/types.ts
242
- var D = class extends Error {
241
+ var O = class extends Error {
243
242
  constructor(e, t) {
244
243
  super(t), this.name = "PybaraError", this.code = e;
245
244
  }
246
- }, O = class {
245
+ }, k = class {
247
246
  constructor(e) {
248
- this.adminClient = null, this.fiatRate = 1, this.modal = null, this.gate = null, this.isOpen = !1, this.activePayment = null, this.config = A(e), this.ready = this.init();
247
+ this.adminClient = null, this.fiatRate = 1, this.modal = null, this.gate = null, this.isOpen = !1, this.activePayment = null, this.config = M(e), this.ready = this.init();
249
248
  }
250
249
  async open(e) {
251
- if (await this.ready, this.gate && !this.gate.show) throw new D("GATE_REFUSED", this.gate.reason ?? "This site cannot accept Pybara payments yet.");
250
+ if (await this.ready, this.gate && !this.gate.show) throw new O("GATE_REFUSED", this.gate.reason ?? "This site cannot accept Pybara payments yet.");
252
251
  let t = e.amount;
253
- if (!Number.isFinite(t) || t <= 0) throw new D("INVALID_CONFIG", `Invalid amount: ${e.amount}`);
252
+ if (!Number.isFinite(t) || t <= 0) throw new O("INVALID_CONFIG", `Invalid amount: ${e.amount}`);
254
253
  let n = e.currency ?? this.config.currency, r = t * (n === "USD" ? 1 : this.fiatRate);
255
- if (r < .5) throw new D("BELOW_MINIMUM", `Minimum payment is $${C} USD.`);
256
- let i = k(e);
254
+ if (r < .5) throw new O("BELOW_MINIMUM", `Minimum payment is $${C} USD.`);
255
+ let i = A(e);
256
+ if (i && this.gate && this.gate.show && !this.gate.recurring) throw new O("GATE_REFUSED", "Recurring payments are temporarily unavailable.");
257
257
  if (this.isOpen) return;
258
258
  this.isOpen = !0;
259
259
  let a = !1;
@@ -264,12 +264,12 @@ var D = class extends Error {
264
264
  }
265
265
  this.modal || this.initCheckoutModal();
266
266
  let o = this.modal;
267
- if (!o) throw this.isOpen = !1, new D("CHECKOUT_FAILED", "The checkout modal could not be initialised.");
267
+ if (!o) throw this.isOpen = !1, new O("CHECKOUT_FAILED", "The checkout modal could not be initialised.");
268
268
  a ? (this.isOpen = !1, o.renderTerminalState("This recipient is currently unable to accept donations."), this.initCheckoutModal()) : (this.activePayment = e, o.show({
269
269
  modalData: {
270
270
  amountUSD: r,
271
271
  beneficiary: this.config.recipientPrincipal,
272
- salt: j(),
272
+ salt: N(),
273
273
  reference: this.config.siteName
274
274
  },
275
275
  recurring: i,
@@ -292,7 +292,7 @@ var D = class extends Error {
292
292
  } catch (e) {
293
293
  r && console.error("🧩 pybara-js: admin client init failed:", e);
294
294
  }
295
- this.config.pluginVersion || (this.gate = await E(t, window.location.origin, this.config.recipientPrincipal), !this.gate.show && r && console.warn("🧩 pybara-js: gate refused —", this.gate.reason)), this.preconnectWallet(t), this.initCheckoutModal();
295
+ this.config.pluginVersion || (this.gate = await D(t, this.config.siteUrl, this.config.recipientPrincipal), !this.gate.show && r && console.warn("🧩 pybara-js: gate refused —", this.gate.reason)), this.preconnectWallet(t), this.initCheckoutModal();
296
296
  }
297
297
  initCheckoutModal() {
298
298
  let e = this.config.staging ? "staging" : "prod", n = this.config, r = this;
@@ -301,7 +301,7 @@ var D = class extends Error {
301
301
  context: "donation",
302
302
  thankYouMessage: n.thankYouMessage,
303
303
  onSuccess: (e) => {
304
- let t = r.activePayment, i = t ? k(t) : void 0, a = {
304
+ let t = r.activePayment, i = t ? A(t) : void 0, a = {
305
305
  blockIndex: e.blockIndex,
306
306
  reference: e.reference,
307
307
  token: e.token,
@@ -317,7 +317,7 @@ var D = class extends Error {
317
317
  onError: (e) => {
318
318
  r.isOpen = !1;
319
319
  let t = r.activePayment;
320
- r.activePayment = null, t?.onError?.(M(e)), r.modal = null, r.initCheckoutModal();
320
+ r.activePayment = null, t?.onError?.(P(e)), r.modal = null, r.initCheckoutModal();
321
321
  },
322
322
  onClose: () => {
323
323
  r.isOpen = !1;
@@ -360,42 +360,57 @@ var D = class extends Error {
360
360
  n.rel = "preconnect", n.href = new URL(t[e]).origin, n.crossOrigin = "anonymous", document.head.appendChild(n);
361
361
  }
362
362
  };
363
- function k(e) {
363
+ function A(e) {
364
364
  if (!e.frequency) return;
365
365
  let t = b[e.frequency], n = e.durationMonths;
366
366
  if (n == null) return {
367
367
  frequency: e.frequency,
368
368
  totalPulls: 0
369
369
  };
370
- if (!S.includes(n)) throw new D("INVALID_CONFIG", `durationMonths must be one of ${S.join(", ")} — got ${n}.`);
370
+ if (!S.includes(n)) throw new O("INVALID_CONFIG", `durationMonths must be one of ${S.join(", ")} — got ${n}.`);
371
371
  return {
372
372
  frequency: e.frequency,
373
373
  totalPulls: Math.ceil(n * x / t),
374
374
  durationMonths: n
375
375
  };
376
376
  }
377
- function A(e) {
378
- if (!e.recipientPrincipal) throw new D("INVALID_CONFIG", "Pybara.checkout: \"recipientPrincipal\" is required");
379
- if (!e.siteUrl) throw new D("INVALID_CONFIG", "Pybara.checkout: \"siteUrl\" is required");
380
- if (!e.siteName) throw new D("INVALID_CONFIG", "Pybara.checkout: \"siteName\" is required");
377
+ function j(e) {
378
+ let t = e.trim();
379
+ if (!t) return null;
380
+ let n;
381
+ try {
382
+ n = new URL(t.includes("://") ? t : `https://${t}`);
383
+ } catch {
384
+ return null;
385
+ }
386
+ return n.protocol !== "https:" && n.protocol !== "http:" ? null : n.origin + n.pathname.replace(/\/+$/, "");
387
+ }
388
+ function M(e) {
389
+ if (!e.recipientPrincipal) throw new O("INVALID_CONFIG", "Pybara.checkout: \"recipientPrincipal\" is required");
390
+ if (!e.siteUrl) throw new O("INVALID_CONFIG", "Pybara.checkout: \"siteUrl\" is required");
391
+ let t = j(e.siteUrl);
392
+ if (!t) throw new O("INVALID_CONFIG", `Pybara.checkout: "siteUrl" is not a valid http(s) URL: ${e.siteUrl}`);
393
+ if (!e.siteName) throw new O("INVALID_CONFIG", "Pybara.checkout: \"siteName\" is required");
381
394
  return {
382
395
  ...e,
396
+ siteUrl: t,
383
397
  currency: e.currency ?? "USD",
384
398
  staging: e.staging ?? !1,
385
399
  debug: e.debug ?? !1
386
400
  };
387
401
  }
388
- function j() {
402
+ function N() {
389
403
  let e = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
390
404
  return btoa(String.fromCharCode(...e));
391
405
  }
392
- function M(e) {
406
+ function P(e) {
393
407
  return e instanceof Error ? e : Error(String(e));
394
408
  }
395
409
  //#endregion
396
410
  //#region src/index.ts
397
- var N = { checkout(e) {
398
- return new O(e);
399
- } };
411
+ function F(e) {
412
+ return new k(e);
413
+ }
414
+ var I = { checkout: F };
400
415
  //#endregion
401
- export { N as Pybara, O as PybaraCheckout, D as PybaraError };
416
+ export { I as Pybara, k as PybaraCheckout, O as PybaraError, F as checkout };
package/package.json CHANGED
@@ -1,7 +1,19 @@
1
1
  {
2
2
  "name": "@pybara/pybara-js",
3
- "version": "0.1.0",
3
+ "version": "0.2.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
+ "keywords": [
6
+ "pybara",
7
+ "payment",
8
+ "payments",
9
+ "crypto",
10
+ "crypto-payments",
11
+ "checkout",
12
+ "donations",
13
+ "icp",
14
+ "internet-computer"
15
+ ],
16
+ "homepage": "https://docs.pybara.com/pybara-js/",
5
17
  "license": "MIT",
6
18
  "type": "module",
7
19
  "main": "./dist/pybara-js.js",
@@ -20,15 +32,18 @@
20
32
  "./package.json": "./package.json"
21
33
  },
22
34
  "files": [
23
- "dist"
35
+ "dist",
36
+ "checkout.schema.json"
24
37
  ],
25
38
  "scripts": {
26
39
  "build": "vite build && vite build -c vite.config.iife.ts",
27
40
  "prepare": "npm run build",
28
41
  "type-check": "tsc --noEmit",
29
- "update:pybara": "npm install -D @pybara/pybara-sdk@github:pybara/pybara-sdk @pybara/pybara-ux@github:pybara/pybara-ux",
42
+ "update:pybara": "npm install -D @pybara/pybara-ux@github:pybara/pybara-ux",
30
43
  "prepublishOnly": "npm run type-check && npm run build",
31
- "release:tag": "git tag v$npm_package_version && git push origin v$npm_package_version"
44
+ "release:tag": "git tag v$npm_package_version && git push origin v$npm_package_version",
45
+ "demo": "node demo/load-env.mjs && (sleep 1 && open http://localhost:5678 &) && npx serve demo -l 5678",
46
+ "dev": "vite --open /demo/"
32
47
  },
33
48
  "devDependencies": {
34
49
  "@biomejs/biome": "2.5.15",