@zuplo/zudoku-plugin-monetization 0.0.44 → 0.0.45

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.
Files changed (2) hide show
  1. package/dist/index.mjs +232 -51
  2. package/package.json +3 -3
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { D as formatDurationAdjective, E as formatDuration, O as formatDurationInterval, T as formatPrice, _ as formatPlanPrice, a as planHasDefaultTaxBehavior, b as sameEntitlementSet, c as getPlanPriceSchedule, d as PlanEntitlements, f as PlanPhaseHeader, l as PlanPriceTag, o as subscriptionTaxLegendSentence, p as EntitlementList, r as isCustomPlan, t as PricingTable, u as PlanPriceSchedule, w as formatMinorCurrencyAmount, x as categorizeRateCards, y as comparePlanEntitlements } from "./PricingTable-WkG2n7V-.mjs";
2
2
  import { cn, createPlugin, joinUrl, throwIfProblemJson } from "zudoku";
3
- import { AlertTriangleIcon, ArrowDownIcon, ArrowLeftRightIcon, ArrowUpIcon, CalendarIcon, CheckCheckIcon, CheckIcon, ChevronDownIcon, CircleSlashIcon, ClockIcon, CreditCardIcon, Grid2x2XIcon, InfoIcon, Loader2Icon, LockIcon, MoreVerticalIcon, RefreshCcw, RefreshCwIcon, Settings, ShieldIcon, StarsIcon, Trash2Icon, XIcon } from "zudoku/icons";
3
+ import { AlertTriangleIcon, ArrowDownIcon, ArrowLeftRightIcon, ArrowUpIcon, BadgePercentIcon, CalendarIcon, CheckCheckIcon, CheckIcon, ChevronDownIcon, CircleSlashIcon, ClockIcon, CreditCardIcon, Grid2x2XIcon, HistoryIcon, InfoIcon, Loader2Icon, LockIcon, MoreVerticalIcon, RefreshCcw, RefreshCwIcon, Settings, ShieldIcon, StarsIcon, Trash2Icon, XIcon } from "zudoku/icons";
4
4
  import { Link, Outlet, useLocation, useNavigate, useSearchParams } from "zudoku/router";
5
5
  import { useAuth, useZudoku } from "zudoku/hooks";
6
6
  import { QueryClient, QueryClientProvider, queryOptions, useMutation, useQuery, useQueryClient, useSuspenseQuery } from "zudoku/react-query";
@@ -1034,6 +1034,24 @@ const useSubscriptions = () => {
1034
1034
  });
1035
1035
  };
1036
1036
  //#endregion
1037
+ //#region src/hooks/usePendingCredits.ts
1038
+ /**
1039
+ * Fetch the operator-applied usage credits for a subscription, via the Zuplo
1040
+ * metering `.../pending-credits` endpoint. Failures are swallowed (`retry: false`,
1041
+ * `throwOnError: false`) so the usage page never breaks when credits are
1042
+ * unavailable — the credit banner simply isn't shown.
1043
+ */
1044
+ const usePendingCredits = (deploymentName, subscriptionId) => {
1045
+ const zudoku = useZudoku();
1046
+ return useQuery({
1047
+ queryKey: [`/v3/zudoku-metering/${deploymentName}/subscriptions/${subscriptionId}/pending-credits`],
1048
+ meta: { context: zudoku },
1049
+ refetchOnWindowFocus: true,
1050
+ retry: false,
1051
+ throwOnError: false
1052
+ });
1053
+ };
1054
+ //#endregion
1037
1055
  //#region src/pages/subscriptions/ConfirmDeleteKeyAlert.tsx
1038
1056
  const ConfirmDeleteKeyAlert = ({ children, onDelete }) => {
1039
1057
  return /* @__PURE__ */ jsxs(AlertDialog, { children: [/* @__PURE__ */ jsx(AlertDialogTrigger, {
@@ -2142,6 +2160,7 @@ const sectionLabelClassName = "text-base font-semibold tracking-wide mb-3 mt-2";
2142
2160
  const formatDateTimeRange = (from, to) => `${formatDateTime(from)} – ${formatDateTime(to)}`;
2143
2161
  const SubscriptionPlanDetails = ({ subscription }) => {
2144
2162
  const { pricing } = useMonetizationConfig();
2163
+ const hasEnded = !!subscription.activeTo && new Date(subscription.activeTo).getTime() < Date.now();
2145
2164
  const plan = subscription.plan;
2146
2165
  const view = getSubscriptionPlanView(subscription, { units: pricing?.units });
2147
2166
  const { priceLabel } = view;
@@ -2195,10 +2214,10 @@ const SubscriptionPlanDetails = ({ subscription }) => {
2195
2214
  }) : null] })] }),
2196
2215
  /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", {
2197
2216
  className: detailLabelClassName,
2198
- children: "Current period"
2217
+ children: hasEnded ? "Ended" : "Current period"
2199
2218
  }), /* @__PURE__ */ jsx("dd", {
2200
2219
  className: "text-foreground",
2201
- children: subscription.alignment?.currentAlignedBillingPeriod ? formatDateTimeRange(subscription.alignment.currentAlignedBillingPeriod.from, subscription.alignment.currentAlignedBillingPeriod.to) : "—"
2220
+ children: hasEnded ? formatDateTime(subscription.activeTo ?? "") : subscription.alignment?.currentAlignedBillingPeriod ? formatDateTimeRange(subscription.alignment.currentAlignedBillingPeriod.from, subscription.alignment.currentAlignedBillingPeriod.to) : "—"
2202
2221
  })] })
2203
2222
  ]
2204
2223
  }),
@@ -2236,48 +2255,185 @@ const SubscriptionPlanDetails = ({ subscription }) => {
2236
2255
  });
2237
2256
  };
2238
2257
  //#endregion
2258
+ //#region src/utils/priceIncludedUnits.ts
2259
+ const partAmount = (part) => {
2260
+ if (!part || part.amount === void 0) return 0;
2261
+ const amount = parseFloat(part.amount);
2262
+ return Number.isFinite(amount) ? amount : Number.POSITIVE_INFINITY;
2263
+ };
2264
+ const priceIncludedUnits = (price) => {
2265
+ if (!price) return 0;
2266
+ if (price.type === "flat" || price.type === "package" || price.type === "dynamic") return 0;
2267
+ if (price.tiers?.length) {
2268
+ if ((price.mode ?? "graduated") !== "graduated") return 0;
2269
+ const sorted = [...price.tiers].sort((a, b) => {
2270
+ if (a.upToAmount === void 0) return 1;
2271
+ if (b.upToAmount === void 0) return -1;
2272
+ return Number(a.upToAmount) - Number(b.upToAmount);
2273
+ });
2274
+ let free = 0;
2275
+ for (const [index, tier] of sorted.entries()) {
2276
+ if (partAmount(tier.unitPrice) > 0) break;
2277
+ if (index > 0 && partAmount(tier.flatPrice) > 0) break;
2278
+ if (tier.upToAmount === void 0) return Number.POSITIVE_INFINITY;
2279
+ const bound = Number(tier.upToAmount);
2280
+ if (!Number.isFinite(bound) || bound <= free) break;
2281
+ free = bound;
2282
+ }
2283
+ return free;
2284
+ }
2285
+ if (price.type === "unit") {
2286
+ const amount = parseFloat(price.amount ?? "");
2287
+ return Number.isFinite(amount) && amount === 0 ? Number.POSITIVE_INFINITY : 0;
2288
+ }
2289
+ return 0;
2290
+ };
2291
+ //#endregion
2292
+ //#region src/pages/subscriptions/deriveUsageView.ts
2293
+ const formatAmount = (amount) => {
2294
+ const value = parseFloat(amount ?? "");
2295
+ return Number.isFinite(value) ? `$${value.toFixed(2)}` : void 0;
2296
+ };
2297
+ const pluralizeUnit = (unitName) => unitName.endsWith("s") ? unitName : `${unitName}s`;
2298
+ /** The label for what additional usage costs, when the shape has one number. */
2299
+ const rateLabelFor = (price, unitName) => {
2300
+ if (!price) return void 0;
2301
+ if (price.type === "unit") {
2302
+ const amount = formatAmount(price.amount);
2303
+ return amount ? `${amount}/${unitName}` : void 0;
2304
+ }
2305
+ if (price.type === "tiered") {
2306
+ const amount = formatAmount((price.tiers?.find((t) => !t.upToAmount) ?? price.tiers?.at(-1))?.unitPrice?.amount);
2307
+ return amount ? `${amount}/${unitName}` : void 0;
2308
+ }
2309
+ if (price.type === "package") {
2310
+ const amount = formatAmount(price.amount);
2311
+ if (!amount) return void 0;
2312
+ const size = parseFloat(price.quantityPerUnit ?? "");
2313
+ return Number.isFinite(size) && size > 0 ? `${amount} per ${size.toLocaleString()} ${pluralizeUnit(unitName)}` : amount;
2314
+ }
2315
+ };
2316
+ const NO_CAP = "There is no usage cap.";
2317
+ const deriveUsageView = (meter, item, unitName = "unit") => {
2318
+ const quota = meter.balance + meter.usage - meter.overage;
2319
+ const isSoftLimit = item?.included?.entitlement?.isSoftLimit ?? true;
2320
+ const rateLabel = rateLabelFor(item?.price, unitName);
2321
+ if (!isSoftLimit) return {
2322
+ kind: "capped",
2323
+ usage: meter.usage,
2324
+ quota,
2325
+ remaining: meter.balance,
2326
+ atLimit: meter.usage >= quota,
2327
+ rateLabel
2328
+ };
2329
+ if (!item) return {
2330
+ kind: "meteredGeneric",
2331
+ usage: meter.usage,
2332
+ quota: quota > 0 ? quota : void 0,
2333
+ caption: "Usage is billed per your plan's pricing."
2334
+ };
2335
+ if (!item.price || item.price.type === "flat") return {
2336
+ kind: "meteredGeneric",
2337
+ usage: meter.usage,
2338
+ quota: quota > 0 ? quota : void 0,
2339
+ caption: `Usage doesn't change your bill. ${NO_CAP}`
2340
+ };
2341
+ const isGraduated = item.price.type === "tiered" && (item.price.mode ?? "graduated") === "graduated";
2342
+ const derivable = item.price.type === "unit" || isGraduated;
2343
+ const freeUnits = priceIncludedUnits(item.price);
2344
+ if (derivable) {
2345
+ if (freeUnits === 0) return {
2346
+ kind: "payAsYouGo",
2347
+ usage: meter.usage,
2348
+ caption: `Pay as you go — every ${unitName} is billed; there is no usage cap.`,
2349
+ rateLabel
2350
+ };
2351
+ if (freeUnits === Number.POSITIVE_INFINITY) return {
2352
+ kind: "meteredGeneric",
2353
+ usage: meter.usage,
2354
+ quota: quota > 0 ? quota : void 0,
2355
+ caption: `Included with your plan. ${NO_CAP}`,
2356
+ rateLabel
2357
+ };
2358
+ if (quota > 0) return {
2359
+ kind: "included",
2360
+ usage: meter.usage,
2361
+ included: quota,
2362
+ remaining: meter.balance,
2363
+ overage: meter.overage,
2364
+ rateLabel
2365
+ };
2366
+ return {
2367
+ kind: "meteredGeneric",
2368
+ usage: meter.usage,
2369
+ caption: `The first ${freeUnits.toLocaleString()} ${pluralizeUnit(unitName)} are included; additional usage is billed. ${NO_CAP}`,
2370
+ rateLabel
2371
+ };
2372
+ }
2373
+ return {
2374
+ kind: "meteredGeneric",
2375
+ usage: meter.usage,
2376
+ quota: quota > 0 ? quota : void 0,
2377
+ caption: `Usage is billed per your plan's pricing. ${NO_CAP}`,
2378
+ rateLabel
2379
+ };
2380
+ };
2381
+ //#endregion
2239
2382
  //#region src/pages/subscriptions/Usage.tsx
2240
2383
  const isMeteredEntitlement = (entitlement) => {
2241
2384
  return "balance" in entitlement;
2242
2385
  };
2243
- const UsageItem = ({ meter, item, subscription, featureKey }) => {
2386
+ const UsageItem = ({ meter, item, subscription, featureKey, pendingCredit }) => {
2387
+ const { pricing } = useMonetizationConfig();
2244
2388
  const cadence = item?.billingCadence ?? subscription?.billingCadence;
2245
2389
  const billingPeriod = cadence ? formatDurationAdjective(cadence) : "monthly";
2246
- const isSoftLimit = item?.included?.entitlement?.isSoftLimit ?? true;
2247
- const rate = (item?.price?.tiers?.find((t) => !t.upToAmount) ?? item?.price?.tiers?.at(-1))?.unitPrice?.amount;
2248
- const hasOverage = meter.overage > 0;
2249
- const limit = meter.balance + meter.usage - meter.overage;
2250
- const isAtLimit = !isSoftLimit && meter.usage >= limit;
2251
- const dangerZone = hasOverage || isAtLimit;
2390
+ const view = deriveUsageView(meter, item, pricing?.units?.[item?.key ?? ""] ?? pricing?.units?.[featureKey] ?? "unit");
2391
+ const atHardLimit = view.kind === "capped" && view.atLimit;
2392
+ const overIncluded = view.kind === "included" && view.overage > 0;
2393
+ const upgradeAction = (variant) => subscription && /* @__PURE__ */ jsx(AlertAction, { children: /* @__PURE__ */ jsx(SwitchPlanModal, {
2394
+ subscription,
2395
+ children: /* @__PURE__ */ jsxs(Button, {
2396
+ variant,
2397
+ size: "xs",
2398
+ children: [/* @__PURE__ */ jsx(ArrowUpIcon, {}), "Upgrade"]
2399
+ })
2400
+ }) });
2252
2401
  return /* @__PURE__ */ jsxs(Card, {
2253
- className: cn(dangerZone && "border-destructive bg-destructive/5"),
2402
+ className: cn(atHardLimit && "border-destructive bg-destructive/5"),
2254
2403
  children: [/* @__PURE__ */ jsxs(CardHeader, { children: [
2255
- hasOverage && isSoftLimit && /* @__PURE__ */ jsxs(Alert, {
2256
- variant: "destructive",
2404
+ pendingCredit && /* @__PURE__ */ jsxs(Alert, {
2257
2405
  className: "mb-4",
2258
2406
  children: [
2259
- /* @__PURE__ */ jsx(AlertTriangleIcon, { className: "size-4 text-red-600 shrink-0" }),
2407
+ /* @__PURE__ */ jsx(BadgePercentIcon, { className: "size-4 text-green-600 shrink-0" }),
2408
+ /* @__PURE__ */ jsx(AlertTitle, { children: "Usage credit applied" }),
2409
+ /* @__PURE__ */ jsxs(AlertDescription, { children: [
2410
+ "A credit of ",
2411
+ pendingCredit.units.toLocaleString(),
2412
+ " ",
2413
+ pendingCredit.units === 1 ? "unit" : "units",
2414
+ " applies to this billing period and will be deducted from your next invoice automatically."
2415
+ ] })
2416
+ ]
2417
+ }),
2418
+ overIncluded && /* @__PURE__ */ jsxs(Alert, {
2419
+ variant: "warning",
2420
+ className: "mb-4",
2421
+ children: [
2422
+ /* @__PURE__ */ jsx(AlertTriangleIcon, { className: "size-4 shrink-0" }),
2260
2423
  /* @__PURE__ */ jsxs(AlertTitle, { children: [
2261
- "You've exceeded your ",
2424
+ "You've used your included ",
2262
2425
  billingPeriod,
2263
- " quota"
2426
+ " usage"
2264
2427
  ] }),
2265
2428
  /* @__PURE__ */ jsxs(AlertDescription, { children: [
2266
- "Additional usage is being charged at the overage rate",
2267
- rate ? ` ($${Number(rate).toFixed(2)}/call)` : "",
2268
- ". Upgrade to a higher plan for more usage."
2429
+ "Additional usage is billed",
2430
+ view.rateLabel ? ` at ${view.rateLabel}` : "",
2431
+ ". Upgrade to a higher plan for more included usage."
2269
2432
  ] }),
2270
- subscription && /* @__PURE__ */ jsx(AlertAction, { children: /* @__PURE__ */ jsx(SwitchPlanModal, {
2271
- subscription,
2272
- children: /* @__PURE__ */ jsxs(Button, {
2273
- variant: "destructive",
2274
- size: "xs",
2275
- children: [/* @__PURE__ */ jsx(ArrowUpIcon, {}), "Upgrade"]
2276
- })
2277
- }) })
2433
+ upgradeAction("outline")
2278
2434
  ]
2279
2435
  }),
2280
- isAtLimit && !isSoftLimit && /* @__PURE__ */ jsxs(Alert, {
2436
+ atHardLimit && /* @__PURE__ */ jsxs(Alert, {
2281
2437
  variant: "destructive",
2282
2438
  className: "mb-4",
2283
2439
  children: [
@@ -2288,58 +2444,79 @@ const UsageItem = ({ meter, item, subscription, featureKey }) => {
2288
2444
  " limit"
2289
2445
  ] }),
2290
2446
  /* @__PURE__ */ jsx(AlertDescription, { children: "Requests beyond your quota are blocked. Upgrade to a higher plan for more usage." }),
2291
- subscription && /* @__PURE__ */ jsx(AlertAction, { children: /* @__PURE__ */ jsx(SwitchPlanModal, {
2292
- subscription,
2293
- children: /* @__PURE__ */ jsxs(Button, {
2294
- variant: "destructive",
2295
- size: "xs",
2296
- children: [/* @__PURE__ */ jsx(ArrowUpIcon, {}), "Upgrade"]
2297
- })
2298
- }) })
2447
+ upgradeAction("destructive")
2299
2448
  ]
2300
2449
  }),
2301
2450
  /* @__PURE__ */ jsx(CardTitle, { children: item?.name ?? featureKey })
2302
- ] }), /* @__PURE__ */ jsxs(CardContent, {
2451
+ ] }), /* @__PURE__ */ jsx(CardContent, {
2303
2452
  className: "space-y-2",
2304
- children: [
2453
+ children: view.kind === "capped" || view.kind === "included" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
2305
2454
  /* @__PURE__ */ jsxs("div", {
2306
2455
  className: "flex items-center justify-between text-sm",
2307
2456
  children: [/* @__PURE__ */ jsx("div", {
2308
2457
  className: "flex flex-col gap-2 mb-2",
2309
2458
  children: /* @__PURE__ */ jsxs("span", {
2310
- className: cn(dangerZone && "text-red-600 font-medium"),
2459
+ className: cn(atHardLimit && "text-red-600 font-medium"),
2311
2460
  children: [
2312
- meter.usage.toLocaleString(),
2461
+ view.usage.toLocaleString(),
2313
2462
  " used",
2314
- hasOverage && isSoftLimit && /* @__PURE__ */ jsxs("span", {
2463
+ view.kind === "included" && view.overage > 0 && /* @__PURE__ */ jsxs("span", {
2315
2464
  className: "ml-1 text-xs",
2316
2465
  children: [
2317
2466
  "(+",
2318
- meter.overage.toLocaleString(),
2467
+ view.overage.toLocaleString(),
2319
2468
  " overage)"
2320
2469
  ]
2321
2470
  })
2322
2471
  ]
2323
2472
  })
2324
- }), /* @__PURE__ */ jsxs("span", {
2473
+ }), /* @__PURE__ */ jsx("span", {
2325
2474
  className: "text-foreground font-medium",
2326
- children: [limit.toLocaleString(), " limit"]
2475
+ children: view.kind === "capped" ? `${view.quota.toLocaleString()} limit` : `${view.included.toLocaleString()} included`
2327
2476
  })]
2328
2477
  }),
2329
2478
  /* @__PURE__ */ jsx(Progress, {
2330
- value: Math.min(100, limit > 0 ? meter.usage / limit * 100 : 100),
2331
- className: cn("mb-3 h-2", dangerZone && "bg-destructive")
2479
+ value: Math.min(100, (view.kind === "capped" ? view.quota : view.included) > 0 ? view.usage / (view.kind === "capped" ? view.quota : view.included) * 100 : 100),
2480
+ className: cn("mb-3 h-2", atHardLimit && "bg-destructive")
2332
2481
  }),
2333
2482
  /* @__PURE__ */ jsxs("p", {
2334
2483
  className: "text-xs text-muted-foreground",
2335
- children: [meter.balance.toLocaleString(), " remaining this billing period"]
2484
+ children: [
2485
+ view.remaining.toLocaleString(),
2486
+ view.kind === "included" ? " included" : "",
2487
+ " remaining this billing period"
2488
+ ]
2336
2489
  })
2337
- ]
2490
+ ] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
2491
+ className: "flex items-center justify-between text-sm",
2492
+ children: [/* @__PURE__ */ jsxs("span", { children: [view.usage.toLocaleString(), " used this billing period"] }), view.kind === "meteredGeneric" && view.quota !== void 0 ? /* @__PURE__ */ jsxs("span", {
2493
+ className: "text-foreground font-medium",
2494
+ children: [view.quota.toLocaleString(), " quota"]
2495
+ }) : view.rateLabel && /* @__PURE__ */ jsx("span", {
2496
+ className: "text-muted-foreground",
2497
+ children: view.rateLabel
2498
+ })]
2499
+ }), /* @__PURE__ */ jsx("p", {
2500
+ className: "text-xs text-muted-foreground",
2501
+ children: view.caption
2502
+ })] })
2338
2503
  })]
2339
2504
  });
2340
2505
  };
2341
- const Usage = ({ usage, isFetching, currentItems, subscription, isPendingFirstPayment }) => {
2506
+ const Usage = ({ usage, isFetching, currentItems, subscription, isPendingFirstPayment, pendingCredits }) => {
2342
2507
  const hasUsage = Object.values(usage.entitlements).some((value) => isMeteredEntitlement(value));
2508
+ if (!!subscription?.activeTo && new Date(subscription.activeTo).getTime() < Date.now()) return /* @__PURE__ */ jsxs("div", {
2509
+ className: "space-y-4",
2510
+ children: [/* @__PURE__ */ jsx(Heading, {
2511
+ level: 3,
2512
+ children: "Usage"
2513
+ }), /* @__PURE__ */ jsxs(Alert, { children: [
2514
+ /* @__PURE__ */ jsx(HistoryIcon, { className: "size-4 shrink-0" }),
2515
+ /* @__PURE__ */ jsx(AlertTitle, { children: "This subscription has ended" }),
2516
+ /* @__PURE__ */ jsx(AlertDescription, { children: "Usage history isn't available yet." })
2517
+ ] })]
2518
+ });
2519
+ const creditByFeature = new Map((pendingCredits ?? []).map((credit) => [credit.featureKey, credit]));
2343
2520
  return /* @__PURE__ */ jsxs("div", {
2344
2521
  className: "space-y-4",
2345
2522
  children: [
@@ -2378,7 +2555,8 @@ const Usage = ({ usage, isFetching, currentItems, subscription, isPendingFirstPa
2378
2555
  featureKey: key,
2379
2556
  meter: { ...value },
2380
2557
  subscription,
2381
- item: currentItems?.find((item) => item.featureKey === key)
2558
+ item: currentItems?.find((item) => item.featureKey === key),
2559
+ pendingCredit: creditByFeature.get(key)
2382
2560
  }, key) : []) : !isFetching && !subscription?.annotations?.["subscription.previous.id"] ? /* @__PURE__ */ jsxs(Alert, {
2383
2561
  variant: "warning",
2384
2562
  children: [
@@ -2401,6 +2579,7 @@ const ActiveSubscription = ({ subscription, deploymentName }) => {
2401
2579
  refetchOnWindowFocus: true,
2402
2580
  meta: { context: zudoku }
2403
2581
  });
2582
+ const pendingCreditsQuery = usePendingCredits(deploymentName, subscription.id);
2404
2583
  const isPendingFirstPayment = usageQuery.data.paymentStatus.isFirstPayment === true && usageQuery.data.paymentStatus.status !== "paid" && usageQuery.data.paymentStatus.status !== "not_required";
2405
2584
  const activePhase = getActivePhase(subscription);
2406
2585
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [
@@ -2419,7 +2598,8 @@ const ActiveSubscription = ({ subscription, deploymentName }) => {
2419
2598
  usage: usageQuery.data,
2420
2599
  isFetching: usageQuery.isFetching,
2421
2600
  subscription,
2422
- isPendingFirstPayment
2601
+ isPendingFirstPayment,
2602
+ pendingCredits: pendingCreditsQuery.data?.pendingCredits
2423
2603
  }),
2424
2604
  subscription?.consumer?.apiKeys && /* @__PURE__ */ jsx(ApiKeysList, {
2425
2605
  isPendingFirstPayment,
@@ -2566,6 +2746,7 @@ const zuploMonetizationPlugin = createPlugin((options = {}) => ({
2566
2746
  if (context.getAuthState().isAuthenticated) queryClient.prefetchQuery(subscriptionsQuery(context));
2567
2747
  },
2568
2748
  getIdentities: async (context) => {
2749
+ if (!context.getAuthState().isAuthenticated) return [];
2569
2750
  return (await queryClient.fetchQuery(subscriptionsQuery(context))).items.flatMap((sub) => sub.status !== "active" ? [] : sub.consumer.apiKeys.flatMap((apiKey) => apiKey.expiresOn && new Date(apiKey.expiresOn) < /* @__PURE__ */ new Date() ? [] : {
2570
2751
  label: `${sub.name} (****${apiKey.key.slice(-5)})`,
2571
2752
  id: apiKey.id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zuplo/zudoku-plugin-monetization",
3
- "version": "0.0.44",
3
+ "version": "0.0.45",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/zuplo/zudoku",
@@ -33,11 +33,11 @@
33
33
  "@testing-library/react": "16.3.2",
34
34
  "@types/react": "19.2.14",
35
35
  "@types/react-dom": "19.2.3",
36
- "happy-dom": "20.9.0",
36
+ "happy-dom": "20.10.2",
37
37
  "react": "19.2.5",
38
38
  "react-dom": "19.2.5",
39
39
  "tsdown": "0.22.0",
40
- "zudoku": "0.79.1"
40
+ "zudoku": "0.81.0"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "react": ">=19.2.0",