@crediball/elements 0.2.0 → 0.3.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.
@@ -331,8 +331,8 @@ var CrediballPaywallElement = class extends CrediballElement {
331
331
  <span class="sym">${escapeHtml(currencySymbolFor(currency))}</span>
332
332
  <input class="custom-input" inputmode="decimal" placeholder="${custom?.minEur ?? ""}" aria-label="Custom amount" />
333
333
  <button class="custom-add" type="button">Add</button>
334
- </div>
335
- <p class="error" hidden></p>` : ""}
334
+ </div>` : ""}
335
+ <p class="error" hidden></p>
336
336
  <button class="close" part="close" type="button">Not now</button>
337
337
  </div>
338
338
  </div>
@@ -352,7 +352,9 @@ var CrediballPaywallElement = class extends CrediballElement {
352
352
  }
353
353
  } else if (kind === "plan") {
354
354
  const plan = plans.find((p) => p.id === btn.dataset.id);
355
- if (plan) this.emit("crediball-select-plan", plan);
355
+ if (plan && this.emit("crediball-select-plan", plan)) {
356
+ void this.startSubscriptionCheckout(plan.id);
357
+ }
356
358
  } else if (kind === "amount") {
357
359
  const amount = Number(btn.dataset.amount);
358
360
  if (this.emit("crediball-topup", { amount })) {
@@ -394,12 +396,24 @@ var CrediballPaywallElement = class extends CrediballElement {
394
396
  this.dispatchEvent(ev);
395
397
  return !ev.defaultPrevented;
396
398
  }
397
- /** Start the built-in Stripe Checkout and redirect. Errors are surfaced in the dialog. */
398
- async startCheckout(input) {
399
- if (!this.client) return;
399
+ returnPath() {
400
+ return typeof window !== "undefined" ? window.location.pathname + window.location.search : void 0;
401
+ }
402
+ /** Start the built-in top-up Checkout and redirect. Errors are surfaced in the dialog. */
403
+ startCheckout(input) {
404
+ if (!this.client) return Promise.resolve();
405
+ return this.redirect(this.client.createCheckout({ ...input, returnPath: this.returnPath() }));
406
+ }
407
+ /** Start the built-in recurring subscription Checkout and redirect. */
408
+ startSubscriptionCheckout(planId) {
409
+ if (!this.client) return Promise.resolve();
410
+ return this.redirect(
411
+ this.client.createSubscriptionCheckout({ planId, returnPath: this.returnPath() })
412
+ );
413
+ }
414
+ async redirect(session) {
400
415
  try {
401
- const returnPath = typeof window !== "undefined" ? window.location.pathname + window.location.search : void 0;
402
- const { url } = await this.client.createCheckout({ ...input, returnPath });
416
+ const { url } = await session;
403
417
  if (typeof window !== "undefined") window.location.assign(url);
404
418
  } catch (err) {
405
419
  const errEl = this.shadow.querySelector(".error");
@@ -122,22 +122,11 @@ var Crediball = (() => {
122
122
  this.costOf = (event) => {
123
123
  return this.store.get().costs[event]?.costCredits;
124
124
  };
125
- this.createCheckout = async (input) => {
126
- const { publishableKey, userId } = this.config;
127
- const res = await fetch(`${this.apiUrl}/public/topup/checkout`, {
128
- method: "POST",
129
- headers: {
130
- "Content-Type": "application/json",
131
- Authorization: `Bearer ${publishableKey}`
132
- },
133
- body: JSON.stringify({ userId, ...input })
134
- });
135
- if (!res.ok) {
136
- const body = await res.json().catch(() => null);
137
- const message = body && typeof body === "object" && "error" in body && String(body.error) || `Checkout request failed with ${res.status}`;
138
- throw new Error(message);
139
- }
140
- return res.json();
125
+ this.createCheckout = (input) => {
126
+ return this.postCheckout("/public/topup/checkout", input);
127
+ };
128
+ this.createSubscriptionCheckout = (input) => {
129
+ return this.postCheckout("/public/subscriptions/checkout", input);
141
130
  };
142
131
  this.refresh = async () => {
143
132
  const { publishableKey, userId } = this.config;
@@ -199,6 +188,23 @@ var Crediball = (() => {
199
188
  this.apiUrl = (config.apiUrl ?? DEFAULT_API_URL).replace(/\/$/, "");
200
189
  this.pollIntervalMs = config.pollIntervalMs ?? DEFAULT_POLL_MS;
201
190
  }
191
+ async postCheckout(path, input) {
192
+ const { publishableKey, userId } = this.config;
193
+ const res = await fetch(`${this.apiUrl}${path}`, {
194
+ method: "POST",
195
+ headers: {
196
+ "Content-Type": "application/json",
197
+ Authorization: `Bearer ${publishableKey}`
198
+ },
199
+ body: JSON.stringify({ userId, ...input })
200
+ });
201
+ if (!res.ok) {
202
+ const body = await res.json().catch(() => null);
203
+ const message = body && typeof body === "object" && "error" in body && String(body.error) || `Checkout request failed with ${res.status}`;
204
+ throw new Error(message);
205
+ }
206
+ return res.json();
207
+ }
202
208
  pause() {
203
209
  this.stopPolling();
204
210
  this.disconnectSse();
@@ -629,8 +635,8 @@ var Crediball = (() => {
629
635
  <span class="sym">${escapeHtml(currencySymbolFor(currency))}</span>
630
636
  <input class="custom-input" inputmode="decimal" placeholder="${custom?.minEur ?? ""}" aria-label="Custom amount" />
631
637
  <button class="custom-add" type="button">Add</button>
632
- </div>
633
- <p class="error" hidden></p>` : ""}
638
+ </div>` : ""}
639
+ <p class="error" hidden></p>
634
640
  <button class="close" part="close" type="button">Not now</button>
635
641
  </div>
636
642
  </div>
@@ -650,7 +656,9 @@ var Crediball = (() => {
650
656
  }
651
657
  } else if (kind === "plan") {
652
658
  const plan = plans.find((p) => p.id === btn.dataset.id);
653
- if (plan) this.emit("crediball-select-plan", plan);
659
+ if (plan && this.emit("crediball-select-plan", plan)) {
660
+ void this.startSubscriptionCheckout(plan.id);
661
+ }
654
662
  } else if (kind === "amount") {
655
663
  const amount = Number(btn.dataset.amount);
656
664
  if (this.emit("crediball-topup", { amount })) {
@@ -692,12 +700,24 @@ var Crediball = (() => {
692
700
  this.dispatchEvent(ev);
693
701
  return !ev.defaultPrevented;
694
702
  }
695
- /** Start the built-in Stripe Checkout and redirect. Errors are surfaced in the dialog. */
696
- async startCheckout(input) {
697
- if (!this.client) return;
703
+ returnPath() {
704
+ return typeof window !== "undefined" ? window.location.pathname + window.location.search : void 0;
705
+ }
706
+ /** Start the built-in top-up Checkout and redirect. Errors are surfaced in the dialog. */
707
+ startCheckout(input) {
708
+ if (!this.client) return Promise.resolve();
709
+ return this.redirect(this.client.createCheckout({ ...input, returnPath: this.returnPath() }));
710
+ }
711
+ /** Start the built-in recurring subscription Checkout and redirect. */
712
+ startSubscriptionCheckout(planId) {
713
+ if (!this.client) return Promise.resolve();
714
+ return this.redirect(
715
+ this.client.createSubscriptionCheckout({ planId, returnPath: this.returnPath() })
716
+ );
717
+ }
718
+ async redirect(session) {
698
719
  try {
699
- const returnPath = typeof window !== "undefined" ? window.location.pathname + window.location.search : void 0;
700
- const { url } = await this.client.createCheckout({ ...input, returnPath });
720
+ const { url } = await session;
701
721
  if (typeof window !== "undefined") window.location.assign(url);
702
722
  } catch (err) {
703
723
  const errEl = this.shadow.querySelector(".error");
package/dist/index.d.ts CHANGED
@@ -92,16 +92,13 @@ declare class CrediballLowCreditWarningElement extends CrediballElement {
92
92
  * subscription-plans catalog. Call `.open()` / `.close()`, or toggle the `open`
93
93
  * attribute.
94
94
  *
95
- * Top-ups pay out of the box: picking a package or entering a custom amount
96
- * starts a Crediball-hosted Stripe Checkout (using the publishable key) and
97
- * redirects — the developer only has to connect payouts in the dashboard. Each
98
- * choice still first dispatches a bubbling, CANCELABLE event
99
- * (`crediball-select-package` / `crediball-topup`); call `event.preventDefault()`
100
- * in a listener to suppress the built-in checkout and run your own flow instead.
101
- *
102
- * Subscription plans have no built-in checkout (they need recurring billing your
103
- * backend sets up): picking one only dispatches `crediball-select-plan` for the
104
- * host to fulfil server-side.
95
+ * Everything pays out of the box: picking a package, entering a custom amount, or
96
+ * choosing a subscription plan starts a Crediball-hosted Stripe Checkout (using the
97
+ * publishable key) and redirects — the developer only has to connect payouts in the
98
+ * dashboard. Subscriptions bill recurringly and grant credits each period. Each
99
+ * choice first dispatches a bubbling, CANCELABLE event (`crediball-select-package` /
100
+ * `crediball-topup` / `crediball-select-plan`); call `event.preventDefault()` in a
101
+ * listener to suppress the built-in checkout and run your own flow instead.
105
102
  */
106
103
  declare class CrediballPaywallElement extends CrediballElement {
107
104
  private shadow;
@@ -112,8 +109,12 @@ declare class CrediballPaywallElement extends CrediballElement {
112
109
  protected render(): void;
113
110
  /** Dispatch a cancelable option event; returns true when the host did NOT preventDefault. */
114
111
  private emit;
115
- /** Start the built-in Stripe Checkout and redirect. Errors are surfaced in the dialog. */
112
+ private returnPath;
113
+ /** Start the built-in top-up Checkout and redirect. Errors are surfaced in the dialog. */
116
114
  private startCheckout;
115
+ /** Start the built-in recurring subscription Checkout and redirect. */
116
+ private startSubscriptionCheckout;
117
+ private redirect;
117
118
  }
118
119
 
119
120
  export { CrediballBalanceElement, CrediballElement, CrediballLowCreditWarningElement, CrediballPaywallElement, CrediballTopUpButtonElement, CrediballUsageElement };
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  CrediballPaywallElement,
6
6
  CrediballTopUpButtonElement,
7
7
  CrediballUsageElement
8
- } from "./chunk-VW5SGSLN.js";
8
+ } from "./chunk-AEVAHMRY.js";
9
9
  export {
10
10
  CrediballBalanceElement,
11
11
  CrediballElement,
package/dist/register.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  CrediballPaywallElement,
5
5
  CrediballTopUpButtonElement,
6
6
  CrediballUsageElement
7
- } from "./chunk-VW5SGSLN.js";
7
+ } from "./chunk-AEVAHMRY.js";
8
8
 
9
9
  // src/register.ts
10
10
  function define(name, ctor) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crediball/elements",
3
- "version": "0.2.0",
3
+ "version": "0.3.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.1.1"
59
+ "@crediball/core": "^0.2.0"
60
60
  },
61
61
  "devDependencies": {
62
62
  "tsup": "^8.3.5",