@crediball/elements 0.6.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.
@@ -187,6 +187,7 @@ var CrediballLowCreditWarningElement = class extends CrediballElement {
187
187
  // src/paywall.ts
188
188
  import { formatMoney, fetchReferral } from "@crediball/core";
189
189
  var CURRENCY_SYMBOLS = { EUR: "\u20AC", USD: "$", GBP: "\xA3" };
190
+ var PERIOD_SUFFIX = { weekly: "wk", monthly: "mo", yearly: "yr" };
190
191
  function currencySymbolFor(currency) {
191
192
  return CURRENCY_SYMBOLS[currency.toUpperCase()] ?? currency;
192
193
  }
@@ -269,6 +270,7 @@ var STYLE = `
269
270
  padding: 10px 18px;
270
271
  border-radius: var(--crediball-radius, 9999px);
271
272
  }
273
+ p.custom-preview { margin: 6px 0 0; font-size: 12px; color: var(--crediball-ink-muted, #7a7a7a); }
272
274
  p.error { margin: 8px 0 0; font-size: 13px; color: var(--crediball-accent, #0066cc); }
273
275
  button.close {
274
276
  width: 100%;
@@ -283,8 +285,29 @@ var STYLE = `
283
285
  padding: 11px 22px;
284
286
  border-radius: var(--crediball-radius, 9999px);
285
287
  }
286
- .referral { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--crediball-hairline, #e0e0e0); }
287
- .referral .eyebrow { margin-bottom: 8px; }
288
+ .autotopup { margin-top: 16px; }
289
+ .autotopup-toggle {
290
+ appearance: none; border: none; cursor: pointer; background: transparent; padding: 0;
291
+ font: inherit; font-size: 12px; color: var(--crediball-ink-muted, #7a7a7a); text-decoration: underline;
292
+ }
293
+ .autotopup-status { margin: 0; font-size: 12px; color: var(--crediball-ink-muted, #7a7a7a); }
294
+ .autotopup-warning { margin: 0; font-size: 12px; color: var(--crediball-accent, #0066cc); }
295
+ .autotopup-row { display: flex; gap: 8px; align-items: center; }
296
+ .autotopup-row select, .autotopup-row input {
297
+ font: inherit; font-size: 13px; padding: 6px 10px;
298
+ border-radius: var(--crediball-radius, 9999px); border: 1px solid var(--crediball-hairline, #e0e0e0);
299
+ background: var(--crediball-canvas, #ffffff); color: var(--crediball-ink, #1d1d1f);
300
+ }
301
+ .autotopup-row select { flex: 1; min-width: 0; }
302
+ .autotopup-row input { width: 72px; }
303
+ button.autotopup-submit {
304
+ appearance: none; border: none; cursor: pointer; flex: none;
305
+ background: var(--crediball-accent, #0066cc); color: var(--crediball-on-accent, #ffffff);
306
+ font: inherit; font-size: 13px; padding: 6px 14px; border-radius: var(--crediball-radius, 9999px);
307
+ }
308
+ .autotopup-hint { margin: 6px 0 0; font-size: 11px; color: var(--crediball-ink-muted, #7a7a7a); }
309
+ .referral { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--crediball-hairline, #e0e0e0); }
310
+ .referral-label { margin-bottom: 8px; font-size: 12px; font-weight: 600; color: var(--crediball-ink-muted, #7a7a7a); }
288
311
  .referral-row { display: flex; gap: 8px; align-items: center; }
289
312
  .referral-row .link {
290
313
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
@@ -304,6 +327,7 @@ var CrediballPaywallElement = class extends CrediballElement {
304
327
  super();
305
328
  this.referral = null;
306
329
  this.referralCopied = false;
330
+ this.autoTopupOpen = false;
307
331
  this.shadow = this.attachShadow({ mode: "open" });
308
332
  }
309
333
  static get observedAttributes() {
@@ -377,7 +401,7 @@ var CrediballPaywallElement = class extends CrediballElement {
377
401
  (p) => `
378
402
  <button class="option" data-kind="plan" data-id="${escapeHtml(p.id)}">
379
403
  <span>${escapeHtml(p.name)}</span>
380
- <span class="meta">${formatMoney(p.price, currency)}/${p.period === "monthly" ? "mo" : "yr"} \xB7 ${formatCredits(p.credits)} cr</span>
404
+ <span class="meta">${formatMoney(p.price, currency)}/${PERIOD_SUFFIX[p.period] ?? p.period} \xB7 ${formatCredits(p.credits)} cr</span>
381
405
  </button>`
382
406
  ).join("")}
383
407
  </div>` : ""}
@@ -399,16 +423,23 @@ var CrediballPaywallElement = class extends CrediballElement {
399
423
  <span class="sym">${escapeHtml(currencySymbolFor(currency))}</span>
400
424
  <input class="custom-input" inputmode="decimal" placeholder="${custom?.minEur ?? ""}" aria-label="Custom amount" />
401
425
  <button class="custom-add" type="button">${escapeHtml(addButtonText)}</button>
402
- </div>` : ""}
426
+ </div>
427
+ <p class="custom-preview" hidden></p>` : ""}
428
+ ${this.renderAutoTopup(packages, pkgs?.autoTopup, currency)}
403
429
  <p class="error" hidden></p>
430
+ <button class="close" part="close" type="button">Not now</button>
404
431
  ${this.referral?.link ? `<div class="referral">
405
- <div class="eyebrow">${this.referral.rewardCredits && this.referral.rewardCredits > 0 ? `Refer a friend \xB7 earn ${formatCredits(this.referral.rewardCredits)} credits` : "Refer a friend"}</div>
432
+ <div class="referral-label">${escapeHtml(
433
+ (this.getAttribute("referral-label") ?? "Refer a friend \xB7 earn {credits} credits").replace(
434
+ "{credits}",
435
+ formatCredits(this.referral.rewardCredits ?? 0)
436
+ )
437
+ )}</div>
406
438
  <div class="referral-row">
407
439
  <div class="link" title="${escapeHtml(this.referral.link)}">${escapeHtml(this.referral.link)}</div>
408
440
  <button class="referral-copy" type="button">${this.referralCopied ? "Copied!" : "Copy"}</button>
409
441
  </div>
410
442
  </div>` : ""}
411
- <button class="close" part="close" type="button">Not now</button>
412
443
  </div>
413
444
  </div>
414
445
  `;
@@ -443,6 +474,18 @@ var CrediballPaywallElement = class extends CrediballElement {
443
474
  const input = this.shadow.querySelector(".custom-input");
444
475
  const addBtn = this.shadow.querySelector(".custom-add");
445
476
  const errEl = this.shadow.querySelector(".error");
477
+ const previewEl = this.shadow.querySelector(".custom-preview");
478
+ const rate = custom?.rate;
479
+ input?.addEventListener("input", () => {
480
+ if (!previewEl) return;
481
+ const amount = Number(input.value);
482
+ if (!rate || rate <= 0 || !Number.isFinite(amount) || amount <= 0) {
483
+ previewEl.hidden = true;
484
+ return;
485
+ }
486
+ previewEl.hidden = false;
487
+ previewEl.textContent = `\u2248 ${formatCredits(Math.round(amount * rate))} credits`;
488
+ });
446
489
  const submit = () => {
447
490
  const amount = Number(input?.value);
448
491
  const sym = currencySymbolFor(currency);
@@ -465,6 +508,66 @@ var CrediballPaywallElement = class extends CrediballElement {
465
508
  if (e.key === "Enter") submit();
466
509
  });
467
510
  }
511
+ this.shadow.querySelector("[data-open-autotopup]")?.addEventListener("click", () => {
512
+ this.autoTopupOpen = true;
513
+ this.render();
514
+ });
515
+ this.shadow.querySelector(".autotopup-submit")?.addEventListener("click", () => {
516
+ const packageId = this.shadow.querySelector(".autotopup-package")?.value;
517
+ const thresholdCredits = Number(
518
+ this.shadow.querySelector(".autotopup-threshold")?.value
519
+ );
520
+ if (!packageId || !Number.isFinite(thresholdCredits) || thresholdCredits < 0) return;
521
+ if (this.emit("crediball-enable-autotopup", { packageId, thresholdCredits })) {
522
+ void this.startAutoTopupCheckout(packageId, thresholdCredits);
523
+ }
524
+ });
525
+ const fixBtn = this.shadow.querySelector("[data-fix-package]");
526
+ fixBtn?.addEventListener("click", () => {
527
+ const packageId = fixBtn.dataset.fixPackage;
528
+ const thresholdCredits = Number(fixBtn.dataset.fixThreshold);
529
+ if (!packageId || !Number.isFinite(thresholdCredits)) return;
530
+ if (this.emit("crediball-enable-autotopup", { packageId, thresholdCredits })) {
531
+ void this.startAutoTopupCheckout(packageId, thresholdCredits);
532
+ }
533
+ });
534
+ }
535
+ /** HTML for the auto-topup opt-in row / status line / needs_auth-fix prompt. */
536
+ renderAutoTopup(packages, autoTopup, currency) {
537
+ if (!packages.length) return "";
538
+ if (autoTopup?.enabled && autoTopup.status === "active") {
539
+ const pkg = packages.find((p) => p.id === autoTopup.packageId);
540
+ return `<div class="autotopup"><p class="autotopup-status">Auto top-up is on \u2014 buying ${escapeHtml(
541
+ pkg?.name ?? "your package"
542
+ )} whenever your balance drops below ${formatCredits(autoTopup.thresholdCredits)} credits.</p></div>`;
543
+ }
544
+ if (autoTopup?.enabled && (autoTopup.status === "needs_auth" || autoTopup.status === "failed")) {
545
+ const message = autoTopup.status === "needs_auth" ? "Auto top-up needs you to re-confirm your payment method." : "Auto top-up's last charge failed.";
546
+ return `<div class="autotopup">
547
+ <p class="autotopup-warning">${escapeHtml(message)}</p>
548
+ <button class="autotopup-toggle" type="button" data-fix-package="${escapeHtml(
549
+ autoTopup.packageId
550
+ )}" data-fix-threshold="${autoTopup.thresholdCredits}">Fix auto top-up</button>
551
+ </div>`;
552
+ }
553
+ if (this.autoTopupOpen) {
554
+ const cheapest = packages.reduce((min, p) => p.price < min.price ? p : min, packages[0]);
555
+ return `<div class="autotopup">
556
+ <div class="autotopup-row">
557
+ <select class="autotopup-package" aria-label="Package">
558
+ ${packages.map(
559
+ (p) => `<option value="${escapeHtml(p.id)}">${escapeHtml(p.name)} \xB7 ${formatMoney(p.price, currency)}</option>`
560
+ ).join("")}
561
+ </select>
562
+ <input class="autotopup-threshold" inputmode="numeric" aria-label="Threshold credits" value="${cheapest.credits}" />
563
+ <button class="autotopup-submit" type="button">Turn on</button>
564
+ </div>
565
+ <p class="autotopup-hint">Buy that package automatically whenever your balance drops below the credit amount above.</p>
566
+ </div>`;
567
+ }
568
+ return `<div class="autotopup">
569
+ <button class="autotopup-toggle" type="button" data-open-autotopup>Keep me topped up automatically</button>
570
+ </div>`;
468
571
  }
469
572
  /** Copy the invite link to the clipboard, with a 2s "Copied!" confirmation. */
470
573
  async copyReferral() {
@@ -499,6 +602,17 @@ var CrediballPaywallElement = class extends CrediballElement {
499
602
  this.client.createSubscriptionCheckout({ planId, returnPath: this.returnPath() })
500
603
  );
501
604
  }
605
+ /**
606
+ * Start the built-in auto-topup setup Checkout and redirect. No money changes
607
+ * hands here — it only saves a payment method Crediball charges later,
608
+ * off-session, whenever the balance drops below `thresholdCredits`.
609
+ */
610
+ startAutoTopupCheckout(packageId, thresholdCredits) {
611
+ if (!this.client) return Promise.resolve();
612
+ return this.redirect(
613
+ this.client.createAutoTopupCheckout({ packageId, thresholdCredits, returnPath: this.returnPath() })
614
+ );
615
+ }
502
616
  async redirect(session) {
503
617
  try {
504
618
  const { url } = await session;
@@ -133,6 +133,9 @@ var Crediball = (() => {
133
133
  this.createSubscriptionCheckout = (input) => {
134
134
  return this.postCheckout("/public/subscriptions/checkout", input);
135
135
  };
136
+ this.createAutoTopupCheckout = (input) => {
137
+ return this.postCheckout("/public/autotopup/setup", input);
138
+ };
136
139
  this.refresh = async () => {
137
140
  const { publishableKey, userId } = this.config;
138
141
  const headers = { Authorization: `Bearer ${publishableKey}` };
@@ -598,6 +601,7 @@ var Crediball = (() => {
598
601
 
599
602
  // src/paywall.ts
600
603
  var CURRENCY_SYMBOLS = { EUR: "\u20AC", USD: "$", GBP: "\xA3" };
604
+ var PERIOD_SUFFIX = { weekly: "wk", monthly: "mo", yearly: "yr" };
601
605
  function currencySymbolFor(currency) {
602
606
  return CURRENCY_SYMBOLS[currency.toUpperCase()] ?? currency;
603
607
  }
@@ -680,6 +684,7 @@ var Crediball = (() => {
680
684
  padding: 10px 18px;
681
685
  border-radius: var(--crediball-radius, 9999px);
682
686
  }
687
+ p.custom-preview { margin: 6px 0 0; font-size: 12px; color: var(--crediball-ink-muted, #7a7a7a); }
683
688
  p.error { margin: 8px 0 0; font-size: 13px; color: var(--crediball-accent, #0066cc); }
684
689
  button.close {
685
690
  width: 100%;
@@ -694,8 +699,29 @@ var Crediball = (() => {
694
699
  padding: 11px 22px;
695
700
  border-radius: var(--crediball-radius, 9999px);
696
701
  }
697
- .referral { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--crediball-hairline, #e0e0e0); }
698
- .referral .eyebrow { margin-bottom: 8px; }
702
+ .autotopup { margin-top: 16px; }
703
+ .autotopup-toggle {
704
+ appearance: none; border: none; cursor: pointer; background: transparent; padding: 0;
705
+ font: inherit; font-size: 12px; color: var(--crediball-ink-muted, #7a7a7a); text-decoration: underline;
706
+ }
707
+ .autotopup-status { margin: 0; font-size: 12px; color: var(--crediball-ink-muted, #7a7a7a); }
708
+ .autotopup-warning { margin: 0; font-size: 12px; color: var(--crediball-accent, #0066cc); }
709
+ .autotopup-row { display: flex; gap: 8px; align-items: center; }
710
+ .autotopup-row select, .autotopup-row input {
711
+ font: inherit; font-size: 13px; padding: 6px 10px;
712
+ border-radius: var(--crediball-radius, 9999px); border: 1px solid var(--crediball-hairline, #e0e0e0);
713
+ background: var(--crediball-canvas, #ffffff); color: var(--crediball-ink, #1d1d1f);
714
+ }
715
+ .autotopup-row select { flex: 1; min-width: 0; }
716
+ .autotopup-row input { width: 72px; }
717
+ button.autotopup-submit {
718
+ appearance: none; border: none; cursor: pointer; flex: none;
719
+ background: var(--crediball-accent, #0066cc); color: var(--crediball-on-accent, #ffffff);
720
+ font: inherit; font-size: 13px; padding: 6px 14px; border-radius: var(--crediball-radius, 9999px);
721
+ }
722
+ .autotopup-hint { margin: 6px 0 0; font-size: 11px; color: var(--crediball-ink-muted, #7a7a7a); }
723
+ .referral { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--crediball-hairline, #e0e0e0); }
724
+ .referral-label { margin-bottom: 8px; font-size: 12px; font-weight: 600; color: var(--crediball-ink-muted, #7a7a7a); }
699
725
  .referral-row { display: flex; gap: 8px; align-items: center; }
700
726
  .referral-row .link {
701
727
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
@@ -715,6 +741,7 @@ var Crediball = (() => {
715
741
  super();
716
742
  this.referral = null;
717
743
  this.referralCopied = false;
744
+ this.autoTopupOpen = false;
718
745
  this.shadow = this.attachShadow({ mode: "open" });
719
746
  }
720
747
  static get observedAttributes() {
@@ -788,7 +815,7 @@ var Crediball = (() => {
788
815
  (p) => `
789
816
  <button class="option" data-kind="plan" data-id="${escapeHtml(p.id)}">
790
817
  <span>${escapeHtml(p.name)}</span>
791
- <span class="meta">${formatMoney(p.price, currency)}/${p.period === "monthly" ? "mo" : "yr"} \xB7 ${formatCredits(p.credits)} cr</span>
818
+ <span class="meta">${formatMoney(p.price, currency)}/${PERIOD_SUFFIX[p.period] ?? p.period} \xB7 ${formatCredits(p.credits)} cr</span>
792
819
  </button>`
793
820
  ).join("")}
794
821
  </div>` : ""}
@@ -810,16 +837,23 @@ var Crediball = (() => {
810
837
  <span class="sym">${escapeHtml(currencySymbolFor(currency))}</span>
811
838
  <input class="custom-input" inputmode="decimal" placeholder="${custom?.minEur ?? ""}" aria-label="Custom amount" />
812
839
  <button class="custom-add" type="button">${escapeHtml(addButtonText)}</button>
813
- </div>` : ""}
840
+ </div>
841
+ <p class="custom-preview" hidden></p>` : ""}
842
+ ${this.renderAutoTopup(packages, pkgs?.autoTopup, currency)}
814
843
  <p class="error" hidden></p>
844
+ <button class="close" part="close" type="button">Not now</button>
815
845
  ${this.referral?.link ? `<div class="referral">
816
- <div class="eyebrow">${this.referral.rewardCredits && this.referral.rewardCredits > 0 ? `Refer a friend \xB7 earn ${formatCredits(this.referral.rewardCredits)} credits` : "Refer a friend"}</div>
846
+ <div class="referral-label">${escapeHtml(
847
+ (this.getAttribute("referral-label") ?? "Refer a friend \xB7 earn {credits} credits").replace(
848
+ "{credits}",
849
+ formatCredits(this.referral.rewardCredits ?? 0)
850
+ )
851
+ )}</div>
817
852
  <div class="referral-row">
818
853
  <div class="link" title="${escapeHtml(this.referral.link)}">${escapeHtml(this.referral.link)}</div>
819
854
  <button class="referral-copy" type="button">${this.referralCopied ? "Copied!" : "Copy"}</button>
820
855
  </div>
821
856
  </div>` : ""}
822
- <button class="close" part="close" type="button">Not now</button>
823
857
  </div>
824
858
  </div>
825
859
  `;
@@ -854,6 +888,18 @@ var Crediball = (() => {
854
888
  const input = this.shadow.querySelector(".custom-input");
855
889
  const addBtn = this.shadow.querySelector(".custom-add");
856
890
  const errEl = this.shadow.querySelector(".error");
891
+ const previewEl = this.shadow.querySelector(".custom-preview");
892
+ const rate = custom?.rate;
893
+ input?.addEventListener("input", () => {
894
+ if (!previewEl) return;
895
+ const amount = Number(input.value);
896
+ if (!rate || rate <= 0 || !Number.isFinite(amount) || amount <= 0) {
897
+ previewEl.hidden = true;
898
+ return;
899
+ }
900
+ previewEl.hidden = false;
901
+ previewEl.textContent = `\u2248 ${formatCredits(Math.round(amount * rate))} credits`;
902
+ });
857
903
  const submit = () => {
858
904
  const amount = Number(input?.value);
859
905
  const sym = currencySymbolFor(currency);
@@ -876,6 +922,66 @@ var Crediball = (() => {
876
922
  if (e.key === "Enter") submit();
877
923
  });
878
924
  }
925
+ this.shadow.querySelector("[data-open-autotopup]")?.addEventListener("click", () => {
926
+ this.autoTopupOpen = true;
927
+ this.render();
928
+ });
929
+ this.shadow.querySelector(".autotopup-submit")?.addEventListener("click", () => {
930
+ const packageId = this.shadow.querySelector(".autotopup-package")?.value;
931
+ const thresholdCredits = Number(
932
+ this.shadow.querySelector(".autotopup-threshold")?.value
933
+ );
934
+ if (!packageId || !Number.isFinite(thresholdCredits) || thresholdCredits < 0) return;
935
+ if (this.emit("crediball-enable-autotopup", { packageId, thresholdCredits })) {
936
+ void this.startAutoTopupCheckout(packageId, thresholdCredits);
937
+ }
938
+ });
939
+ const fixBtn = this.shadow.querySelector("[data-fix-package]");
940
+ fixBtn?.addEventListener("click", () => {
941
+ const packageId = fixBtn.dataset.fixPackage;
942
+ const thresholdCredits = Number(fixBtn.dataset.fixThreshold);
943
+ if (!packageId || !Number.isFinite(thresholdCredits)) return;
944
+ if (this.emit("crediball-enable-autotopup", { packageId, thresholdCredits })) {
945
+ void this.startAutoTopupCheckout(packageId, thresholdCredits);
946
+ }
947
+ });
948
+ }
949
+ /** HTML for the auto-topup opt-in row / status line / needs_auth-fix prompt. */
950
+ renderAutoTopup(packages, autoTopup, currency) {
951
+ if (!packages.length) return "";
952
+ if (autoTopup?.enabled && autoTopup.status === "active") {
953
+ const pkg = packages.find((p) => p.id === autoTopup.packageId);
954
+ return `<div class="autotopup"><p class="autotopup-status">Auto top-up is on \u2014 buying ${escapeHtml(
955
+ pkg?.name ?? "your package"
956
+ )} whenever your balance drops below ${formatCredits(autoTopup.thresholdCredits)} credits.</p></div>`;
957
+ }
958
+ if (autoTopup?.enabled && (autoTopup.status === "needs_auth" || autoTopup.status === "failed")) {
959
+ const message = autoTopup.status === "needs_auth" ? "Auto top-up needs you to re-confirm your payment method." : "Auto top-up's last charge failed.";
960
+ return `<div class="autotopup">
961
+ <p class="autotopup-warning">${escapeHtml(message)}</p>
962
+ <button class="autotopup-toggle" type="button" data-fix-package="${escapeHtml(
963
+ autoTopup.packageId
964
+ )}" data-fix-threshold="${autoTopup.thresholdCredits}">Fix auto top-up</button>
965
+ </div>`;
966
+ }
967
+ if (this.autoTopupOpen) {
968
+ const cheapest = packages.reduce((min, p) => p.price < min.price ? p : min, packages[0]);
969
+ return `<div class="autotopup">
970
+ <div class="autotopup-row">
971
+ <select class="autotopup-package" aria-label="Package">
972
+ ${packages.map(
973
+ (p) => `<option value="${escapeHtml(p.id)}">${escapeHtml(p.name)} \xB7 ${formatMoney(p.price, currency)}</option>`
974
+ ).join("")}
975
+ </select>
976
+ <input class="autotopup-threshold" inputmode="numeric" aria-label="Threshold credits" value="${cheapest.credits}" />
977
+ <button class="autotopup-submit" type="button">Turn on</button>
978
+ </div>
979
+ <p class="autotopup-hint">Buy that package automatically whenever your balance drops below the credit amount above.</p>
980
+ </div>`;
981
+ }
982
+ return `<div class="autotopup">
983
+ <button class="autotopup-toggle" type="button" data-open-autotopup>Keep me topped up automatically</button>
984
+ </div>`;
879
985
  }
880
986
  /** Copy the invite link to the clipboard, with a 2s "Copied!" confirmation. */
881
987
  async copyReferral() {
@@ -910,6 +1016,17 @@ var Crediball = (() => {
910
1016
  this.client.createSubscriptionCheckout({ planId, returnPath: this.returnPath() })
911
1017
  );
912
1018
  }
1019
+ /**
1020
+ * Start the built-in auto-topup setup Checkout and redirect. No money changes
1021
+ * hands here — it only saves a payment method Crediball charges later,
1022
+ * off-session, whenever the balance drops below `thresholdCredits`.
1023
+ */
1024
+ startAutoTopupCheckout(packageId, thresholdCredits) {
1025
+ if (!this.client) return Promise.resolve();
1026
+ return this.redirect(
1027
+ this.client.createAutoTopupCheckout({ packageId, thresholdCredits, returnPath: this.returnPath() })
1028
+ );
1029
+ }
913
1030
  async redirect(session) {
914
1031
  try {
915
1032
  const { url } = await session;
package/dist/index.d.ts CHANGED
@@ -112,6 +112,7 @@ declare class CrediballPaywallElement extends CrediballElement {
112
112
  private shadow;
113
113
  private referral;
114
114
  private referralCopied;
115
+ private autoTopupOpen;
115
116
  static get observedAttributes(): string[];
116
117
  constructor();
117
118
  connectedCallback(): void;
@@ -121,6 +122,8 @@ declare class CrediballPaywallElement extends CrediballElement {
121
122
  open(): void;
122
123
  close(): void;
123
124
  protected render(): void;
125
+ /** HTML for the auto-topup opt-in row / status line / needs_auth-fix prompt. */
126
+ private renderAutoTopup;
124
127
  /** Copy the invite link to the clipboard, with a 2s "Copied!" confirmation. */
125
128
  private copyReferral;
126
129
  /** Dispatch a cancelable option event; returns true when the host did NOT preventDefault. */
@@ -130,6 +133,12 @@ declare class CrediballPaywallElement extends CrediballElement {
130
133
  private startCheckout;
131
134
  /** Start the built-in recurring subscription Checkout and redirect. */
132
135
  private startSubscriptionCheckout;
136
+ /**
137
+ * Start the built-in auto-topup setup Checkout and redirect. No money changes
138
+ * hands here — it only saves a payment method Crediball charges later,
139
+ * off-session, whenever the balance drops below `thresholdCredits`.
140
+ */
141
+ private startAutoTopupCheckout;
133
142
  private redirect;
134
143
  }
135
144
 
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  CrediballReferralCardElement,
7
7
  CrediballTopUpButtonElement,
8
8
  CrediballUsageElement
9
- } from "./chunk-MWB56UEW.js";
9
+ } from "./chunk-YCLIZG7D.js";
10
10
  export {
11
11
  CrediballBalanceElement,
12
12
  CrediballElement,
package/dist/register.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  CrediballReferralCardElement,
6
6
  CrediballTopUpButtonElement,
7
7
  CrediballUsageElement
8
- } from "./chunk-MWB56UEW.js";
8
+ } from "./chunk-YCLIZG7D.js";
9
9
 
10
10
  // src/register.ts
11
11
  function define(name, ctor) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crediball/elements",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Framework-agnostic web components for showing Crediball credits inside your AI app.",
5
5
  "license": "MIT",
6
6
  "author": "Filippo Rezzadore <filipporezzadore@gmail.com>",
@@ -56,7 +56,7 @@
56
56
  "prepublishOnly": "npm run build"
57
57
  },
58
58
  "dependencies": {
59
- "@crediball/core": "^0.4.0"
59
+ "@crediball/core": "^0.7.0"
60
60
  },
61
61
  "devDependencies": {
62
62
  "tsup": "^8.3.5",