@xapps-platform/marketplace-ui 0.1.8 → 0.1.9

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/index.js CHANGED
@@ -4242,6 +4242,365 @@ function RequestsPage() {
4242
4242
  import { useEffect as useEffect9, useMemo as useMemo8, useRef, useState as useState7 } from "react";
4243
4243
  import { Link as Link9, useLocation as useLocation7, useNavigate as useNavigate3, useParams as useParams2 } from "react-router-dom";
4244
4244
 
4245
+ // ../browser-host/src/xms.ts
4246
+ function readString4(value) {
4247
+ return String(value ?? "").trim();
4248
+ }
4249
+ function readNumber(value, fallback = 0) {
4250
+ const parsed = Number(value);
4251
+ return Number.isFinite(parsed) ? parsed : fallback;
4252
+ }
4253
+ function readLower(value) {
4254
+ return readString4(value).toLowerCase();
4255
+ }
4256
+ function readBoolean(value, fallback = false) {
4257
+ return typeof value === "boolean" ? value : fallback;
4258
+ }
4259
+ function readLocalizedText(value, fallback = "") {
4260
+ if (typeof value === "string") {
4261
+ return readString4(value) || fallback;
4262
+ }
4263
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
4264
+ return fallback;
4265
+ }
4266
+ const record = value;
4267
+ return readString4(record.en) || readString4(record.ro) || Object.values(record).map((item) => readString4(item)).find(Boolean) || fallback;
4268
+ }
4269
+ function formatStateLabel(value, fallback = "\u2014") {
4270
+ const raw = readString4(value);
4271
+ if (!raw) return fallback;
4272
+ return raw.replace(/_/g, " ");
4273
+ }
4274
+ function listXappMonetizationPaywalls(items) {
4275
+ return (Array.isArray(items) ? items : []).filter((item) => item && typeof item === "object" && !Array.isArray(item)).map((item) => item);
4276
+ }
4277
+ function buildPaywallPlacementCandidates(value) {
4278
+ const raw = readLower(value);
4279
+ if (!raw) return [];
4280
+ const out = /* @__PURE__ */ new Set([raw]);
4281
+ if (raw === "paywall" || raw === "default_paywall") {
4282
+ out.add("paywall");
4283
+ out.add("default_paywall");
4284
+ }
4285
+ if (raw === "feature_paywall" || raw === "feature_gate") {
4286
+ out.add("feature_paywall");
4287
+ out.add("feature_gate");
4288
+ }
4289
+ if (raw === "upgrade" || raw === "upgrade_paywall") {
4290
+ out.add("upgrade");
4291
+ out.add("upgrade_paywall");
4292
+ }
4293
+ if (raw === "retention" || raw === "retention_paywall") {
4294
+ out.add("retention");
4295
+ out.add("retention_paywall");
4296
+ }
4297
+ if (raw === "checkout" || raw === "checkout_entry") {
4298
+ out.add("checkout");
4299
+ out.add("checkout_entry");
4300
+ }
4301
+ return Array.from(out);
4302
+ }
4303
+ function selectXappMonetizationPaywall(input) {
4304
+ const paywalls = listXappMonetizationPaywalls(input.paywalls);
4305
+ const slug = readLower(input.slug);
4306
+ const placement = readLower(input.placement);
4307
+ if (slug) {
4308
+ const matched = paywalls.find((item) => readLower(item.slug) === slug);
4309
+ if (matched) return matched;
4310
+ }
4311
+ if (placement) {
4312
+ const candidates = buildPaywallPlacementCandidates(placement);
4313
+ const matched = paywalls.find((item) => candidates.includes(readLower(item.placement)));
4314
+ if (matched) return matched;
4315
+ }
4316
+ return paywalls[0] || null;
4317
+ }
4318
+ function flattenXappMonetizationPaywallPackages(paywall) {
4319
+ const record = paywall && typeof paywall === "object" && !Array.isArray(paywall) ? paywall : {};
4320
+ const out = [];
4321
+ for (const pkg of Array.isArray(record.packages) ? record.packages : []) {
4322
+ const packageRecord = pkg && typeof pkg === "object" && !Array.isArray(pkg) ? pkg : {};
4323
+ const price = Array.isArray(packageRecord.prices) ? packageRecord.prices[0] || null : null;
4324
+ out.push({
4325
+ offeringId: readString4(packageRecord.offering_id),
4326
+ offeringSlug: readString4(packageRecord.offering_slug),
4327
+ offeringTitle: readString4(packageRecord.offering_slug) || "Offering",
4328
+ offeringPlacement: readString4(packageRecord.offering_placement) || null,
4329
+ packageId: readString4(packageRecord.id),
4330
+ packageSlug: readString4(packageRecord.slug),
4331
+ packageTitle: readString4(packageRecord.slug) || "Package",
4332
+ packageKind: readString4(packageRecord.package_kind) || "standard",
4333
+ productId: readString4(packageRecord.product?.id),
4334
+ productSlug: readString4(packageRecord.product?.slug),
4335
+ productFamily: readString4(
4336
+ packageRecord.product?.product_family
4337
+ ),
4338
+ priceId: readString4(price?.id),
4339
+ amount: readString4(price?.amount),
4340
+ currency: readString4(price?.currency),
4341
+ billingPeriod: readString4(price?.billing_period) || null,
4342
+ purchasePolicy: readProjectedPurchasePolicy(packageRecord.purchase_policy),
4343
+ metadata: packageRecord.metadata && typeof packageRecord.metadata === "object" ? packageRecord.metadata : {}
4344
+ });
4345
+ }
4346
+ return out.filter((item) => item.offeringId && item.packageId && item.priceId);
4347
+ }
4348
+ function formatPlacementLabel(value, fallback = "General placement") {
4349
+ const raw = readString4(value);
4350
+ if (!raw) return fallback;
4351
+ return raw.replace(/[_-]+/g, " ");
4352
+ }
4353
+ function readPackageCredits(item) {
4354
+ const metadata = item.metadata && typeof item.metadata === "object" && !Array.isArray(item.metadata) ? item.metadata : {};
4355
+ const direct = readNumber(item.credits ?? metadata.credits, -1);
4356
+ if (direct > 0) return direct;
4357
+ const included = readNumber(metadata.included_credits, -1);
4358
+ if (included > 0) return included;
4359
+ return 0;
4360
+ }
4361
+ function buildMonetizationOfferingPresentation(input) {
4362
+ const record = input && typeof input === "object" && !Array.isArray(input) ? input : {};
4363
+ const offeringLabel = readString4(record.offeringTitle) || formatStateLabel(record.offeringSlug, "Offering");
4364
+ const placementRaw = readLower(record.offeringPlacement);
4365
+ const placementLabel = formatPlacementLabel(record.offeringPlacement);
4366
+ let summary = "General offering surface for this xapp.";
4367
+ if (placementRaw.includes("feature") && placementRaw.includes("paywall")) {
4368
+ summary = "Feature-paywall placement for gated in-app flows.";
4369
+ } else if (placementRaw.includes("paywall")) {
4370
+ summary = "Default paywall placement for monetized upgrade prompts.";
4371
+ } else if (placementRaw.includes("checkout")) {
4372
+ summary = "Direct checkout placement for purchase-driven flows.";
4373
+ } else if (placementRaw.includes("upgrade")) {
4374
+ summary = "Upgrade-oriented placement for membership and package switching.";
4375
+ }
4376
+ return {
4377
+ offeringLabel,
4378
+ placementLabel,
4379
+ summary
4380
+ };
4381
+ }
4382
+ function buildMonetizationPaywallPresentation(input) {
4383
+ const record = input && typeof input === "object" && !Array.isArray(input) ? input : {};
4384
+ const paywallLabel = readLocalizedText(record.title, formatStateLabel(record.slug, "Paywall")) || "Paywall";
4385
+ const placementLabel = formatPlacementLabel(record.placement);
4386
+ const packages = flattenXappMonetizationPaywallPackages(record);
4387
+ const defaultPackageRef = readString4(record.default_package_ref);
4388
+ const defaultPackage = packages.find((item) => readString4(item.packageSlug) === defaultPackageRef) || packages[0] || null;
4389
+ const summary = readLocalizedText(record.description) || (placementLabel === "General placement" ? "Presentation surface for monetized package selection." : `${placementLabel} surface for monetized package selection.`);
4390
+ return {
4391
+ paywallLabel,
4392
+ placementLabel,
4393
+ summary,
4394
+ defaultPackageLabel: defaultPackage ? readString4(defaultPackage.packageTitle) : "",
4395
+ packageCountLabel: `${packages.length} package${packages.length === 1 ? "" : "s"}`
4396
+ };
4397
+ }
4398
+ function buildMonetizationPaywallRenderModel(input) {
4399
+ const record = input && typeof input === "object" && !Array.isArray(input) ? input : {};
4400
+ const presentation = buildMonetizationPaywallPresentation(record);
4401
+ const defaultPackageRef = readString4(record.default_package_ref);
4402
+ const packages = flattenXappMonetizationPaywallPackages(record).map((item) => {
4403
+ const packagePresentation = buildMonetizationPackagePresentation(item);
4404
+ return {
4405
+ packageId: readString4(item.packageId),
4406
+ packageSlug: readString4(item.packageSlug),
4407
+ packageTitle: readString4(item.packageTitle) || "Package",
4408
+ productId: readString4(item.productId),
4409
+ productSlug: readString4(item.productSlug),
4410
+ productFamily: readString4(item.productFamily),
4411
+ metadata: item.metadata && typeof item.metadata === "object" && !Array.isArray(item.metadata) ? item.metadata : {},
4412
+ description: readString4(item.description) || packagePresentation.summary,
4413
+ fitLabel: packagePresentation.fitLabel,
4414
+ moneyLabel: packagePresentation.moneyLabel,
4415
+ offeringLabel: packagePresentation.offeringLabel,
4416
+ placementLabel: packagePresentation.placementLabel,
4417
+ signals: packagePresentation.signals,
4418
+ isDefault: Boolean(defaultPackageRef) && readString4(item.packageSlug) === defaultPackageRef
4419
+ };
4420
+ });
4421
+ const badges = [presentation.placementLabel, presentation.packageCountLabel];
4422
+ if (presentation.defaultPackageLabel) {
4423
+ badges.push(`default ${presentation.defaultPackageLabel}`);
4424
+ }
4425
+ return {
4426
+ ...presentation,
4427
+ badges,
4428
+ packages
4429
+ };
4430
+ }
4431
+ function buildMonetizationPackagePresentation(input) {
4432
+ const item = input && typeof input === "object" && !Array.isArray(input) ? input : {};
4433
+ const packageKind = readString4(item.packageKind);
4434
+ const packageSlug = readLower(item.packageSlug);
4435
+ const metadata = item.metadata && typeof item.metadata === "object" && !Array.isArray(item.metadata) ? item.metadata : {};
4436
+ const credits = readPackageCredits(item);
4437
+ const moneyLabel = normalizeMoneyLabel(item);
4438
+ const offeringPresentation = buildMonetizationOfferingPresentation(item);
4439
+ let fitLabel = "General upgrade";
4440
+ let summary = "Useful as a general monetization upgrade for this creator scope.";
4441
+ if (packageKind === "one_time_unlock") {
4442
+ fitLabel = "Durable unlock";
4443
+ summary = "Best when the feature mainly needs current access without ongoing membership.";
4444
+ } else if (packageKind === "subscription") {
4445
+ fitLabel = "Recurring membership";
4446
+ summary = "Best when the feature depends on ongoing membership coverage.";
4447
+ } else if (packageKind === "credit_pack") {
4448
+ fitLabel = "Credit top-up";
4449
+ summary = "Best when the feature spends credits for each advanced action.";
4450
+ } else if (packageSlug.includes("hybrid")) {
4451
+ fitLabel = "Hybrid upgrade";
4452
+ summary = "Blends access coverage with bundled credits for mixed workflows.";
4453
+ }
4454
+ const signals = [];
4455
+ if (readString4(metadata.badge)) {
4456
+ signals.push(readString4(metadata.badge));
4457
+ }
4458
+ if (credits > 0) {
4459
+ signals.push(`${credits} credits`);
4460
+ }
4461
+ if (readString4(item.billingPeriod)) {
4462
+ signals.push(`billed ${readString4(item.billingPeriod)}`);
4463
+ }
4464
+ if (offeringPresentation.offeringLabel) {
4465
+ signals.push(offeringPresentation.offeringLabel);
4466
+ }
4467
+ if (offeringPresentation.placementLabel && offeringPresentation.placementLabel !== "General placement") {
4468
+ signals.push(offeringPresentation.placementLabel);
4469
+ }
4470
+ return {
4471
+ fitLabel,
4472
+ summary,
4473
+ signals,
4474
+ moneyLabel,
4475
+ offeringLabel: offeringPresentation.offeringLabel,
4476
+ placementLabel: offeringPresentation.placementLabel,
4477
+ offeringSummary: offeringPresentation.summary
4478
+ };
4479
+ }
4480
+ function collectPackageOwnershipCandidates(item) {
4481
+ const metadata = item.metadata && typeof item.metadata === "object" && !Array.isArray(item.metadata) ? item.metadata : {};
4482
+ return [
4483
+ readLower(item.productSlug),
4484
+ readLower(item.packageSlug),
4485
+ readLower(metadata.tier),
4486
+ readLower(metadata.access_tier)
4487
+ ].filter(Boolean);
4488
+ }
4489
+ function hasActiveRecurringSubscription(currentSubscription) {
4490
+ const record = currentSubscription && typeof currentSubscription === "object" && !Array.isArray(currentSubscription) ? currentSubscription : {};
4491
+ const status = readLower(record.status);
4492
+ if (!status || status === "expired") return false;
4493
+ const expiredAt = readString4(record.expired_at);
4494
+ if (!expiredAt) return true;
4495
+ const expiresAtMs = Date.parse(expiredAt);
4496
+ return Number.isNaN(expiresAtMs) || expiresAtMs > Date.now();
4497
+ }
4498
+ function hasCurrentOwnedEntitlement(entitlement) {
4499
+ const status = readLower(entitlement.status);
4500
+ if (status !== "active" && status !== "grace_period") return false;
4501
+ const expiresAt = readString4(entitlement.expires_at);
4502
+ if (!expiresAt) return true;
4503
+ const expiresAtMs = Date.parse(expiresAt);
4504
+ return Number.isNaN(expiresAtMs) || expiresAtMs > Date.now();
4505
+ }
4506
+ function readProjectedPurchasePolicy(value) {
4507
+ const record = value && typeof value === "object" && !Array.isArray(value) ? value : null;
4508
+ if (!record) return null;
4509
+ const status = readLower(record.status);
4510
+ const transitionKind = readLower(record.transition_kind ?? record.transitionKind);
4511
+ if (!status || !transitionKind) return null;
4512
+ return {
4513
+ canPurchase: readBoolean(record.can_purchase ?? record.canPurchase, true),
4514
+ status: status === "current_recurring_plan" || status === "owned_additive_unlock" ? status : "available",
4515
+ transitionKind: transitionKind === "start_recurring" || transitionKind === "replace_recurring" || transitionKind === "buy_additive_unlock" || transitionKind === "buy_credit_pack" || transitionKind === "activate_hybrid" ? transitionKind : "none",
4516
+ reason: readString4(record.reason) || null
4517
+ };
4518
+ }
4519
+ function resolveMonetizationPackagePurchasePolicy(input) {
4520
+ const item = input.item && typeof input.item === "object" ? input.item : {};
4521
+ const projectedPolicy = readProjectedPurchasePolicy(item.purchasePolicy ?? item.purchase_policy);
4522
+ if (projectedPolicy) return projectedPolicy;
4523
+ const currentSubscription = input.currentSubscription && typeof input.currentSubscription === "object" && !Array.isArray(input.currentSubscription) ? input.currentSubscription : {};
4524
+ const additiveEntitlements = Array.isArray(input.additiveEntitlements) ? input.additiveEntitlements : [];
4525
+ const productFamily = readLower(item.productFamily);
4526
+ const packageKind = readLower(item.packageKind);
4527
+ const productId = readLower(item.productId);
4528
+ const currentSubscriptionProductId = readLower(currentSubscription.product_id);
4529
+ const ownershipCandidates = new Set(collectPackageOwnershipCandidates(item));
4530
+ const ownedAdditiveUnlock = additiveEntitlements.some((entry) => {
4531
+ const entitlement = entry && typeof entry === "object" && !Array.isArray(entry) ? entry : {};
4532
+ if (!hasCurrentOwnedEntitlement(entitlement)) return false;
4533
+ const entitlementProductId = readLower(entitlement.product_id);
4534
+ if (productId && entitlementProductId && productId === entitlementProductId) return true;
4535
+ const candidateValues = [
4536
+ readLower(entitlement.product_slug),
4537
+ readLower(entitlement.tier)
4538
+ ].filter(Boolean);
4539
+ return candidateValues.some((value) => ownershipCandidates.has(value));
4540
+ });
4541
+ if (hasActiveRecurringSubscription(currentSubscription) && productId && currentSubscriptionProductId && productId === currentSubscriptionProductId) {
4542
+ return {
4543
+ canPurchase: false,
4544
+ status: "current_recurring_plan",
4545
+ transitionKind: "none",
4546
+ reason: "current_recurring_plan"
4547
+ };
4548
+ }
4549
+ if ((productFamily === "one_time_unlock" || packageKind === "one_time_unlock") && ownedAdditiveUnlock) {
4550
+ return {
4551
+ canPurchase: false,
4552
+ status: "owned_additive_unlock",
4553
+ transitionKind: "none",
4554
+ reason: "owned_additive_unlock"
4555
+ };
4556
+ }
4557
+ if (productFamily === "credit_pack" || packageKind === "credit_pack") {
4558
+ return {
4559
+ canPurchase: true,
4560
+ status: "available",
4561
+ transitionKind: "buy_credit_pack",
4562
+ reason: null
4563
+ };
4564
+ }
4565
+ if (productFamily === "one_time_unlock" || packageKind === "one_time_unlock") {
4566
+ return {
4567
+ canPurchase: true,
4568
+ status: "available",
4569
+ transitionKind: "buy_additive_unlock",
4570
+ reason: null
4571
+ };
4572
+ }
4573
+ if (productFamily === "subscription_plan" || packageKind === "subscription") {
4574
+ return {
4575
+ canPurchase: true,
4576
+ status: "available",
4577
+ transitionKind: hasActiveRecurringSubscription(currentSubscription) ? "replace_recurring" : "start_recurring",
4578
+ reason: null
4579
+ };
4580
+ }
4581
+ if (productFamily === "hybrid_plan") {
4582
+ return {
4583
+ canPurchase: true,
4584
+ status: "available",
4585
+ transitionKind: "activate_hybrid",
4586
+ reason: null
4587
+ };
4588
+ }
4589
+ return {
4590
+ canPurchase: true,
4591
+ status: "available",
4592
+ transitionKind: "none",
4593
+ reason: null
4594
+ };
4595
+ }
4596
+ function normalizeMoneyLabel(item) {
4597
+ const amount = readString4(item.amount);
4598
+ const currency = readString4(item.currency);
4599
+ const billingPeriod = readString4(item.billingPeriod);
4600
+ if (!amount && !currency) return "Price unavailable";
4601
+ return `${amount} ${currency}${billingPeriod ? ` / ${billingPeriod}` : ""}`.trim();
4602
+ }
4603
+
4245
4604
  // src/utils/monetizationAccess.ts
4246
4605
  function asRecord5(value) {
4247
4606
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
@@ -4310,17 +4669,49 @@ function asRecord6(value) {
4310
4669
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
4311
4670
  return value;
4312
4671
  }
4313
- function readString4(value) {
4672
+ function readString5(value) {
4314
4673
  return typeof value === "string" ? value.trim() : "";
4315
4674
  }
4316
- function readBoolean(value, fallback) {
4675
+ function readBoolean2(value, fallback) {
4317
4676
  return typeof value === "boolean" ? value : fallback;
4318
4677
  }
4319
- function readNumber(value) {
4678
+ function readNumber2(value) {
4320
4679
  return typeof value === "number" && Number.isFinite(value) ? value : null;
4321
4680
  }
4681
+ function buildMonetizationCheckoutReturnUrl(input) {
4682
+ const url = new URL(input.currentHref, window.location.href);
4683
+ url.searchParams.set("focus", "plans");
4684
+ url.searchParams.set("xapps_monetization_intent_id", input.intentId);
4685
+ if (input.packageSlug) {
4686
+ url.searchParams.set("paywallPackage", input.packageSlug);
4687
+ }
4688
+ return url.toString();
4689
+ }
4690
+ function navigateToHostedCheckout(url) {
4691
+ const target = String(url || "").trim();
4692
+ if (!target) return;
4693
+ try {
4694
+ if (typeof window !== "undefined" && window.top && window.top !== window) {
4695
+ window.top.location.assign(target);
4696
+ return;
4697
+ }
4698
+ } catch {
4699
+ }
4700
+ window.location.assign(target);
4701
+ }
4702
+ function stripMonetizationCheckoutReturnParams(search) {
4703
+ const next = new URLSearchParams(search);
4704
+ const keysToDelete = [];
4705
+ for (const key of next.keys()) {
4706
+ if (key.startsWith("xapps_payment_")) keysToDelete.push(key);
4707
+ }
4708
+ keysToDelete.push("xapps_monetization_intent_id");
4709
+ for (const key of keysToDelete) next.delete(key);
4710
+ const rendered = next.toString();
4711
+ return rendered ? `?${rendered}` : "";
4712
+ }
4322
4713
  function formatDateTime2(value, locale) {
4323
- const raw = readString4(value);
4714
+ const raw = readString5(value);
4324
4715
  if (!raw) return "";
4325
4716
  const parsed = new Date(raw);
4326
4717
  if (Number.isNaN(parsed.getTime())) return raw;
@@ -4339,28 +4730,28 @@ function formatDateTime2(value, locale) {
4339
4730
  function normalizeUsageCreditSummary(value) {
4340
4731
  const summary = asRecord6(value);
4341
4732
  if (!summary) return null;
4342
- const availableCount = readNumber(summary.available_count) ?? 0;
4343
- const availableSessionBackedCount = readNumber(summary.available_session_backed_count) ?? 0;
4344
- const availableLedgerOnlyCount = readNumber(summary.available_ledger_only_count) ?? 0;
4345
- const reservedCount = readNumber(summary.reserved_count) ?? 0;
4346
- const reservedActiveCount = readNumber(summary.reserved_active_count) ?? reservedCount;
4347
- const reservedStaleCount = readNumber(summary.reserved_stale_count) ?? 0;
4348
- const consumedCount = readNumber(summary.consumed_count) ?? 0;
4733
+ const availableCount = readNumber2(summary.available_count) ?? 0;
4734
+ const availableSessionBackedCount = readNumber2(summary.available_session_backed_count) ?? 0;
4735
+ const availableLedgerOnlyCount = readNumber2(summary.available_ledger_only_count) ?? 0;
4736
+ const reservedCount = readNumber2(summary.reserved_count) ?? 0;
4737
+ const reservedActiveCount = readNumber2(summary.reserved_active_count) ?? reservedCount;
4738
+ const reservedStaleCount = readNumber2(summary.reserved_stale_count) ?? 0;
4739
+ const consumedCount = readNumber2(summary.consumed_count) ?? 0;
4349
4740
  const byToolRaw = Array.isArray(summary.by_tool) ? summary.by_tool : [];
4350
4741
  const byTool = byToolRaw.map((entry) => {
4351
4742
  const record = asRecord6(entry);
4352
4743
  if (!record) return null;
4353
- const toolName = readString4(record.tool_name);
4744
+ const toolName = readString5(record.tool_name);
4354
4745
  if (!toolName) return null;
4355
4746
  return {
4356
4747
  tool_name: toolName,
4357
- available_count: readNumber(record.available_count) ?? 0,
4358
- available_session_backed_count: readNumber(record.available_session_backed_count) ?? 0,
4359
- available_ledger_only_count: readNumber(record.available_ledger_only_count) ?? 0,
4360
- reserved_count: readNumber(record.reserved_count) ?? 0,
4361
- reserved_active_count: readNumber(record.reserved_active_count) ?? readNumber(record.reserved_count) ?? 0,
4362
- reserved_stale_count: readNumber(record.reserved_stale_count) ?? 0,
4363
- consumed_count: readNumber(record.consumed_count) ?? 0
4748
+ available_count: readNumber2(record.available_count) ?? 0,
4749
+ available_session_backed_count: readNumber2(record.available_session_backed_count) ?? 0,
4750
+ available_ledger_only_count: readNumber2(record.available_ledger_only_count) ?? 0,
4751
+ reserved_count: readNumber2(record.reserved_count) ?? 0,
4752
+ reserved_active_count: readNumber2(record.reserved_active_count) ?? readNumber2(record.reserved_count) ?? 0,
4753
+ reserved_stale_count: readNumber2(record.reserved_stale_count) ?? 0,
4754
+ consumed_count: readNumber2(record.consumed_count) ?? 0
4364
4755
  };
4365
4756
  }).filter((entry) => Boolean(entry)).filter(
4366
4757
  (entry) => entry.available_count > 0 || entry.available_ledger_only_count > 0 || entry.reserved_active_count > 0 || entry.reserved_stale_count > 0
@@ -4376,14 +4767,14 @@ function normalizeUsageCreditSummary(value) {
4376
4767
  reserved_active_count: reservedActiveCount,
4377
4768
  reserved_stale_count: reservedStaleCount,
4378
4769
  consumed_count: consumedCount,
4379
- updated_at: readString4(summary.updated_at) || null,
4770
+ updated_at: readString5(summary.updated_at) || null,
4380
4771
  by_tool: byTool
4381
4772
  };
4382
4773
  }
4383
4774
  function normalizeGuardPolicyKind(policy) {
4384
4775
  if (policy === "all" || policy === "any") return policy;
4385
4776
  const policyObj = asRecord6(policy);
4386
- const mode = readString4(policyObj?.mode);
4777
+ const mode = readString5(policyObj?.mode);
4387
4778
  return mode === "any" ? "any" : "all";
4388
4779
  }
4389
4780
  function defaultBlockingForTrigger(trigger) {
@@ -4392,6 +4783,47 @@ function defaultBlockingForTrigger(trigger) {
4392
4783
  function humanizeSlug(slug) {
4393
4784
  return String(slug || "").trim().replace(/[_-]+/g, " ").replace(/\s+/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
4394
4785
  }
4786
+ function buildMonetizationHookSummaryItems(manifest) {
4787
+ const monetization = asRecord6(manifest?.monetization);
4788
+ const hooks = asRecord6(monetization?.hooks);
4789
+ const afterPaymentCompleted = asRecord6(
4790
+ hooks?.after_payment_completed ?? hooks?.afterPaymentCompleted
4791
+ );
4792
+ if (!afterPaymentCompleted || readBoolean2(afterPaymentCompleted.enabled, true) === false) {
4793
+ return [];
4794
+ }
4795
+ const baseItems = [];
4796
+ const defaultInvoiceRef = readString5(
4797
+ afterPaymentCompleted.invoice_ref ?? afterPaymentCompleted.invoiceRef
4798
+ );
4799
+ baseItems.push({
4800
+ slug: "xms_after_payment_completed",
4801
+ label: defaultInvoiceRef ? `XMS payment completed \xB7 ${defaultInvoiceRef}` : "XMS payment completed",
4802
+ trigger: "after:payment_completed",
4803
+ headless: true,
4804
+ blocking: false,
4805
+ order: null,
4806
+ policyKind: "all"
4807
+ });
4808
+ const byPaymentGuardRef = asRecord6(
4809
+ afterPaymentCompleted.by_payment_guard_ref ?? afterPaymentCompleted.byPaymentGuardRef
4810
+ );
4811
+ for (const [paymentGuardRef, rawValue] of Object.entries(byPaymentGuardRef ?? {})) {
4812
+ const config = asRecord6(rawValue);
4813
+ if (!config || readBoolean2(config.enabled, true) === false) continue;
4814
+ const invoiceRef = readString5(config.invoice_ref ?? config.invoiceRef);
4815
+ baseItems.push({
4816
+ slug: `xms_after_payment_completed_${paymentGuardRef}`,
4817
+ label: invoiceRef ? `XMS payment completed \xB7 ${paymentGuardRef} \xB7 ${invoiceRef}` : `XMS payment completed \xB7 ${paymentGuardRef}`,
4818
+ trigger: "after:payment_completed",
4819
+ headless: true,
4820
+ blocking: false,
4821
+ order: null,
4822
+ policyKind: "all"
4823
+ });
4824
+ }
4825
+ return baseItems;
4826
+ }
4395
4827
  function humanizeTrigger(trigger, translate) {
4396
4828
  const normalized = String(trigger || "").trim().toLowerCase();
4397
4829
  if (normalized === "before:tool_run") {
@@ -4413,6 +4845,12 @@ function describeGuardChain(policyKind, translate) {
4413
4845
  return policyKind === "any" ? translate("xapp.policy_any", void 0, "Any one satisfies") : translate("xapp.policy_all", void 0, "All steps apply");
4414
4846
  }
4415
4847
  function XappDetailPage() {
4848
+ return /* @__PURE__ */ jsx14(XappDetailPageContent, {});
4849
+ }
4850
+ function XappPlansPage() {
4851
+ return /* @__PURE__ */ jsx14(XappDetailPageContent, { renderMode: "plans_only" });
4852
+ }
4853
+ function XappDetailPageContent(props) {
4416
4854
  const { client, host, env } = useMarketplace();
4417
4855
  const { locale, t } = useMarketplaceI18n();
4418
4856
  const { xappId } = useParams2();
@@ -4420,10 +4858,22 @@ function XappDetailPage() {
4420
4858
  const token = useQueryToken7();
4421
4859
  const action = useQueryAction();
4422
4860
  const queryToolName = useQueryToolName();
4861
+ const routeQuery = useMemo8(() => new URLSearchParams(loc.search), [loc.search]);
4862
+ const routeSource = String(routeQuery.get("from") || "").trim().toLowerCase();
4863
+ const focusedSection = String(routeQuery.get("focus") || "").trim().toLowerCase();
4864
+ const requestedPaywallSlug = String(routeQuery.get("paywall") || "").trim().toLowerCase();
4865
+ const selectedPaywallPackageSlug = String(routeQuery.get("paywallPackage") || "").trim().toLowerCase();
4866
+ const paymentReturnStatus = String(routeQuery.get("xapps_payment_status") || "").trim().toLowerCase();
4867
+ const paymentReturnSessionId = String(routeQuery.get("xapps_payment_session_id") || "").trim();
4868
+ const paymentReturnIntentId = String(routeQuery.get("xapps_monetization_intent_id") || "").trim();
4423
4869
  const tokenSearch = buildTokenSearch(token, loc.search);
4424
4870
  const navigate = useNavigate3();
4425
4871
  const autoOpenedWidgetKeyRef = useRef("");
4872
+ const plansSectionRef = useRef(null);
4426
4873
  const canMutate = host.canMutate ? host.canMutate() : true;
4874
+ const renderMode = props?.renderMode === "plans_only" ? "plans_only" : "full";
4875
+ const plansOnlyMode = renderMode === "plans_only";
4876
+ const widgetHostedPlansMode = plansOnlyMode && routeSource === "widget";
4427
4877
  const addAppLabel = env?.copy?.addAppLabel || t("xapp.add_to_workspace", void 0, "Add to workspace");
4428
4878
  const removeAppLabel = env?.copy?.removeAppLabel || t("xapp.remove_from_workspace", void 0, "Remove from workspace");
4429
4879
  const updateAppLabel = env?.copy?.updateAppLabel || t("xapp.update_app", void 0, "Update app");
@@ -4438,9 +4888,17 @@ function XappDetailPage() {
4438
4888
  const [termsAction, setTermsAction] = useState7("none");
4439
4889
  const [removeConfirmOpen, setRemoveConfirmOpen] = useState7(false);
4440
4890
  const [guardSummaryOpen, setGuardSummaryOpen] = useState7(false);
4891
+ const [checkoutBusyPackageSlug, setCheckoutBusyPackageSlug] = useState7("");
4892
+ const [checkoutError, setCheckoutError] = useState7(null);
4893
+ const [checkoutNotice, setCheckoutNotice] = useState7(null);
4894
+ const checkoutFinalizeKeyRef = useRef("");
4441
4895
  const hasSubject = Boolean(host.subjectId);
4442
4896
  const installationsByXappId = hasSubject ? host.getInstallationsByXappId() : {};
4443
- const installation = xappId ? installationsByXappId[String(xappId)] : null;
4897
+ const routeInstallationId = String(routeQuery.get("installationId") || "").trim();
4898
+ const installation = xappId && installationsByXappId[String(xappId)] ? installationsByXappId[String(xappId)] : xappId && routeInstallationId ? {
4899
+ installationId: routeInstallationId,
4900
+ xappId: String(xappId)
4901
+ } : null;
4444
4902
  const updateAvailable = Boolean(installation?.updateAvailable);
4445
4903
  const widgetsEnabled = Boolean(installation) && !updateAvailable && hasSubject;
4446
4904
  const isEmbedded = window.location.pathname.startsWith("/embed");
@@ -4455,7 +4913,7 @@ function XappDetailPage() {
4455
4913
  });
4456
4914
  setData(asRecord6(res));
4457
4915
  } catch (e) {
4458
- setError(readString4(asRecord6(e)?.message) || String(e));
4916
+ setError(readString5(asRecord6(e)?.message) || String(e));
4459
4917
  } finally {
4460
4918
  setBusy(false);
4461
4919
  }
@@ -4499,7 +4957,10 @@ function XappDetailPage() {
4499
4957
  let cancelled = false;
4500
4958
  void (async () => {
4501
4959
  try {
4502
- const next = await client.getMyXappMonetization(currentXappId);
4960
+ const next = await client.getMyXappMonetization(currentXappId, {
4961
+ installationId: installation?.installationId ?? null,
4962
+ locale
4963
+ });
4503
4964
  if (!cancelled) {
4504
4965
  setMonetization(next);
4505
4966
  }
@@ -4512,23 +4973,23 @@ function XappDetailPage() {
4512
4973
  return () => {
4513
4974
  cancelled = true;
4514
4975
  };
4515
- }, [client, host.subjectId, xappId]);
4976
+ }, [client, host.subjectId, installation?.installationId, xappId]);
4516
4977
  const manifest = asRecord6(data?.manifest);
4517
4978
  const xappRecord = asRecord6(data?.xapp);
4518
4979
  const versionRecord = asRecord6(data?.version);
4519
4980
  const publisherRecord = asRecord6(xappRecord?.publisher);
4520
- const title = resolveMarketplaceText(manifest?.title, locale) || readString4(xappRecord?.name) || t("xapp.kicker_default", void 0, "Xapp");
4521
- const description = resolveMarketplaceText(manifest?.description, locale) || readString4(xappRecord?.description) || "";
4522
- const imageUrl = readString4(manifest?.image) || "https://picsum.photos/seed/xapps-detail/840/360";
4981
+ const title = resolveMarketplaceText(manifest?.title, locale) || readString5(xappRecord?.name) || t("xapp.kicker_default", void 0, "Xapp");
4982
+ const description = resolveMarketplaceText(manifest?.description, locale) || readString5(xappRecord?.description) || "";
4983
+ const imageUrl = readString5(manifest?.image) || "https://picsum.photos/seed/xapps-detail/840/360";
4523
4984
  const widgets = Array.isArray(data?.widgets) ? data.widgets.filter((widget) => Boolean(asRecord6(widget))) : [];
4524
4985
  const defaultWidget = useMemo8(() => {
4525
- const def = widgets.find((w) => readBoolean(w.default, false));
4986
+ const def = widgets.find((w) => readBoolean2(w.default, false));
4526
4987
  return def || widgets[0] || null;
4527
4988
  }, [widgets]);
4528
4989
  const requestedWidget = useMemo8(() => {
4529
- const desiredToolName = readString4(queryToolName);
4990
+ const desiredToolName = readString5(queryToolName);
4530
4991
  if (!desiredToolName) return defaultWidget;
4531
- return widgets.find((widget) => readString4(widget.bind_tool_name) === desiredToolName) || defaultWidget;
4992
+ return widgets.find((widget) => readString5(widget.bind_tool_name) === desiredToolName) || defaultWidget;
4532
4993
  }, [defaultWidget, queryToolName, widgets]);
4533
4994
  const backTo = {
4534
4995
  pathname: isEmbedded ? "/embed/catalog" : "..",
@@ -4536,8 +4997,8 @@ function XappDetailPage() {
4536
4997
  };
4537
4998
  const terms = asRecord6(manifest?.terms);
4538
4999
  const termsTitle = resolveMarketplaceText(terms?.title, locale) || t("xapp.terms_title", void 0, "Terms & Conditions");
4539
- const termsText = resolveMarketplaceText(terms?.text, locale) || readString4(terms?.text);
4540
- const termsUrl = readString4(terms?.url);
5000
+ const termsText = resolveMarketplaceText(terms?.text, locale) || readString5(terms?.text);
5001
+ const termsUrl = readString5(terms?.url);
4541
5002
  const hasTermsContent = Boolean(termsText || termsUrl);
4542
5003
  const requiresTerms = Boolean(terms || action === "install" || action === "update");
4543
5004
  useEffect9(() => {
@@ -4558,13 +5019,13 @@ function XappDetailPage() {
4558
5019
  if (env?.embedMode) return;
4559
5020
  if (!installation || !widgetsEnabled) return;
4560
5021
  const widget = requestedWidget;
4561
- const widgetId = readString4(widget?.id);
5022
+ const widgetId = readString5(widget?.id);
4562
5023
  if (!widgetId) return;
4563
5024
  const key = [
4564
5025
  String(xappId ?? ""),
4565
5026
  installation.installationId,
4566
5027
  widgetId,
4567
- readString4(queryToolName)
5028
+ readString5(queryToolName)
4568
5029
  ].join(":");
4569
5030
  if (autoOpenedWidgetKeyRef.current === key) return;
4570
5031
  autoOpenedWidgetKeyRef.current = key;
@@ -4573,8 +5034,8 @@ function XappDetailPage() {
4573
5034
  widgetId,
4574
5035
  xappId: String(xappId ?? ""),
4575
5036
  xappTitle: String(title),
4576
- widgetName: resolveMarketplaceText(widget?.title, locale) || readString4(widget?.widget_name) || readString4(widget?.name) || t("common.widget", void 0, "Widget"),
4577
- toolName: readString4(widget?.bind_tool_name)
5037
+ widgetName: resolveMarketplaceText(widget?.title, locale) || readString5(widget?.widget_name) || readString5(widget?.name) || t("common.widget", void 0, "Widget"),
5038
+ toolName: readString5(widget?.bind_tool_name)
4578
5039
  });
4579
5040
  }, [
4580
5041
  action,
@@ -4618,8 +5079,8 @@ function XappDetailPage() {
4618
5079
  }
4619
5080
  return t("activity.requests_title", void 0, "Requests");
4620
5081
  }
4621
- const publisherSlug = readString4(publisherRecord?.slug);
4622
- const publisherName = readString4(publisherRecord?.name) || publisherSlug;
5082
+ const publisherSlug = readString5(publisherRecord?.slug);
5083
+ const publisherName = readString5(publisherRecord?.name) || publisherSlug;
4623
5084
  const publisherTo = publisherSlug ? {
4624
5085
  pathname: isEmbedded ? `/publishers/${encodeURIComponent(publisherSlug)}` : `/marketplace/publishers/${encodeURIComponent(publisherSlug)}`,
4625
5086
  search: tokenSearch
@@ -4627,28 +5088,31 @@ function XappDetailPage() {
4627
5088
  const guardSummary = useMemo8(() => {
4628
5089
  const guardsRaw = Array.isArray(manifest?.guards) ? manifest.guards : [];
4629
5090
  const policyMap = asRecord6(manifest?.guards_policy) ?? {};
4630
- const items = guardsRaw.map((raw) => {
5091
+ const guardItems = guardsRaw.map((raw) => {
4631
5092
  const guard = asRecord6(raw);
4632
5093
  if (!guard) return null;
4633
- const trigger = readString4(guard.trigger);
4634
- const slug = readString4(guard.slug);
5094
+ const trigger = readString5(guard.trigger);
5095
+ const slug = readString5(guard.slug);
4635
5096
  if (!trigger || !slug) return null;
4636
5097
  const policyKind = normalizeGuardPolicyKind(policyMap[trigger]);
4637
5098
  return {
4638
5099
  slug,
4639
5100
  trigger,
4640
- headless: readBoolean(guard.headless, true),
4641
- blocking: readBoolean(guard.blocking, defaultBlockingForTrigger(trigger)),
4642
- order: readNumber(guard.order),
5101
+ headless: readBoolean2(guard.headless, true),
5102
+ blocking: readBoolean2(guard.blocking, defaultBlockingForTrigger(trigger)),
5103
+ order: readNumber2(guard.order),
4643
5104
  policyKind
4644
5105
  };
4645
- }).filter((item) => Boolean(item)).sort((a, b) => {
4646
- const orderA = a.order ?? Number.MAX_SAFE_INTEGER;
4647
- const orderB = b.order ?? Number.MAX_SAFE_INTEGER;
4648
- if (orderA !== orderB) return orderA - orderB;
4649
- if (a.trigger !== b.trigger) return a.trigger.localeCompare(b.trigger);
4650
- return a.slug.localeCompare(b.slug);
4651
- });
5106
+ }).filter((item) => Boolean(item));
5107
+ const items = [...guardItems, ...buildMonetizationHookSummaryItems(manifest)].sort(
5108
+ (a, b) => {
5109
+ const orderA = a.order ?? Number.MAX_SAFE_INTEGER;
5110
+ const orderB = b.order ?? Number.MAX_SAFE_INTEGER;
5111
+ if (orderA !== orderB) return orderA - orderB;
5112
+ if (a.trigger !== b.trigger) return a.trigger.localeCompare(b.trigger);
5113
+ return a.slug.localeCompare(b.slug);
5114
+ }
5115
+ );
4652
5116
  const byTrigger = /* @__PURE__ */ new Map();
4653
5117
  for (const item of items) {
4654
5118
  const existing = byTrigger.get(item.trigger) ?? [];
@@ -4662,15 +5126,259 @@ function XappDetailPage() {
4662
5126
  [data?.usage_credit_summary]
4663
5127
  );
4664
5128
  const monetizationAccessProjection = monetization?.access_projection ?? null;
5129
+ const monetizationPaywalls = useMemo8(
5130
+ () => listXappMonetizationPaywalls(monetization?.paywalls),
5131
+ [monetization?.paywalls]
5132
+ );
5133
+ const selectedPaywall = useMemo8(
5134
+ () => monetizationPaywalls.find(
5135
+ (item) => readString5(asRecord6(item)?.slug).trim().toLowerCase() === requestedPaywallSlug
5136
+ ) || selectXappMonetizationPaywall({
5137
+ paywalls: monetizationPaywalls,
5138
+ placement: "default_paywall"
5139
+ }) || selectXappMonetizationPaywall({
5140
+ paywalls: monetizationPaywalls,
5141
+ placement: "paywall"
5142
+ }) || monetizationPaywalls[0] || null,
5143
+ [monetizationPaywalls, requestedPaywallSlug]
5144
+ );
5145
+ const selectedPaywallRenderModel = useMemo8(
5146
+ () => selectedPaywall ? buildMonetizationPaywallRenderModel(selectedPaywall) : null,
5147
+ [selectedPaywall]
5148
+ );
5149
+ const selectedPaywallPackageRecords = useMemo8(
5150
+ () => selectedPaywall ? flattenXappMonetizationPaywallPackages(selectedPaywall) : [],
5151
+ [selectedPaywall]
5152
+ );
5153
+ useEffect9(() => {
5154
+ if (focusedSection !== "plans" || !plansSectionRef.current) return;
5155
+ if (typeof plansSectionRef.current.scrollIntoView === "function") {
5156
+ plansSectionRef.current.scrollIntoView({ behavior: "smooth", block: "start" });
5157
+ }
5158
+ }, [focusedSection]);
5159
+ useEffect9(() => {
5160
+ const currentXappId = String(xappId ?? "").trim();
5161
+ if (!currentXappId || !paymentReturnIntentId || !paymentReturnStatus) return;
5162
+ const handledKey = [
5163
+ currentXappId,
5164
+ paymentReturnIntentId,
5165
+ paymentReturnSessionId,
5166
+ paymentReturnStatus
5167
+ ].join(":");
5168
+ if (checkoutFinalizeKeyRef.current === handledKey) return;
5169
+ checkoutFinalizeKeyRef.current = handledKey;
5170
+ const clearReturnParams = () => {
5171
+ const nextSearch = stripMonetizationCheckoutReturnParams(loc.search);
5172
+ void navigate(
5173
+ {
5174
+ pathname: loc.pathname,
5175
+ search: nextSearch
5176
+ },
5177
+ { replace: true }
5178
+ );
5179
+ };
5180
+ if (paymentReturnStatus === "cancelled" || paymentReturnStatus === "canceled") {
5181
+ setCheckoutError(null);
5182
+ setCheckoutNotice(
5183
+ t("xapp.checkout_cancelled", void 0, "Checkout was cancelled before completion.")
5184
+ );
5185
+ clearReturnParams();
5186
+ return;
5187
+ }
5188
+ if (paymentReturnStatus === "failed") {
5189
+ setCheckoutNotice(null);
5190
+ setCheckoutError(
5191
+ t("xapp.checkout_failed", void 0, "Payment failed before access could be issued.")
5192
+ );
5193
+ clearReturnParams();
5194
+ return;
5195
+ }
5196
+ if (paymentReturnStatus !== "paid" || typeof client.finalizeMyXappPurchasePaymentSession !== "function") {
5197
+ return;
5198
+ }
5199
+ let cancelled = false;
5200
+ setCheckoutNotice(
5201
+ t("xapp.checkout_finalizing", void 0, "Finalizing payment and refreshing access...")
5202
+ );
5203
+ setCheckoutError(null);
5204
+ void (async () => {
5205
+ try {
5206
+ await client.finalizeMyXappPurchasePaymentSession({
5207
+ xappId: currentXappId,
5208
+ intentId: paymentReturnIntentId
5209
+ });
5210
+ if (typeof client.getMyXappMonetization === "function") {
5211
+ const next = await client.getMyXappMonetization(currentXappId, {
5212
+ installationId: installation?.installationId ?? null,
5213
+ locale
5214
+ });
5215
+ if (!cancelled) setMonetization(next);
5216
+ }
5217
+ if (!cancelled) {
5218
+ setCheckoutNotice(
5219
+ t("xapp.checkout_finalized", void 0, "Payment completed and access was refreshed.")
5220
+ );
5221
+ clearReturnParams();
5222
+ }
5223
+ } catch (error2) {
5224
+ if (cancelled) return;
5225
+ const message = readString5(asRecord6(error2)?.message) || (error2 instanceof Error ? error2.message : "") || t(
5226
+ "xapp.checkout_finalize_failed",
5227
+ void 0,
5228
+ "Payment returned, but access refresh did not complete yet."
5229
+ );
5230
+ setCheckoutNotice(null);
5231
+ setCheckoutError(message);
5232
+ }
5233
+ })();
5234
+ return () => {
5235
+ cancelled = true;
5236
+ };
5237
+ }, [
5238
+ client,
5239
+ installation?.installationId,
5240
+ locale,
5241
+ loc.pathname,
5242
+ loc.search,
5243
+ navigate,
5244
+ paymentReturnIntentId,
5245
+ paymentReturnSessionId,
5246
+ paymentReturnStatus,
5247
+ t,
5248
+ xappId
5249
+ ]);
5250
+ async function finalizeCurrentUserCheckoutIntent(currentXappId, intentId) {
5251
+ if (typeof client.finalizeMyXappPurchasePaymentSession !== "function") {
5252
+ throw new Error(
5253
+ t(
5254
+ "xapp.checkout_finalize_unavailable",
5255
+ void 0,
5256
+ "Access refresh is not available for this checkout flow."
5257
+ )
5258
+ );
5259
+ }
5260
+ setCheckoutNotice(
5261
+ t("xapp.checkout_finalizing", void 0, "Finalizing payment and refreshing access...")
5262
+ );
5263
+ setCheckoutError(null);
5264
+ await client.finalizeMyXappPurchasePaymentSession({
5265
+ xappId: currentXappId,
5266
+ intentId
5267
+ });
5268
+ if (typeof client.getMyXappMonetization === "function") {
5269
+ const next = await client.getMyXappMonetization(currentXappId, {
5270
+ installationId: installation?.installationId ?? null,
5271
+ locale
5272
+ });
5273
+ setMonetization(next);
5274
+ }
5275
+ setCheckoutNotice(
5276
+ t("xapp.checkout_finalized", void 0, "Payment completed and access was refreshed.")
5277
+ );
5278
+ }
5279
+ async function startPackageCheckout(packageSlug) {
5280
+ const normalizedSlug = packageSlug.trim().toLowerCase();
5281
+ if (!xappId || typeof client.prepareMyXappPurchaseIntent !== "function" || typeof client.createMyXappPurchasePaymentSession !== "function" || !normalizedSlug) {
5282
+ return;
5283
+ }
5284
+ const pkg = selectedPaywallPackageRecords.find(
5285
+ (item) => readString5(item.packageSlug).trim().toLowerCase() === normalizedSlug
5286
+ );
5287
+ if (pkg) {
5288
+ const purchasePolicy = getPackagePurchasePolicy(pkg);
5289
+ if (!purchasePolicy.canPurchase) {
5290
+ setCheckoutError(
5291
+ purchasePolicy.status === "owned_additive_unlock" ? t(
5292
+ "xapp.checkout_owned_unlock_blocked",
5293
+ void 0,
5294
+ "This add-on unlock is already owned for the current monetization scope."
5295
+ ) : t(
5296
+ "xapp.checkout_current_plan_blocked",
5297
+ void 0,
5298
+ "This plan is already active for the current monetization scope."
5299
+ )
5300
+ );
5301
+ return;
5302
+ }
5303
+ }
5304
+ const offeringId = readString5(pkg?.offeringId);
5305
+ const packageId = readString5(pkg?.packageId);
5306
+ const priceId = readString5(pkg?.priceId);
5307
+ if (!offeringId || !packageId || !priceId) {
5308
+ setCheckoutError(
5309
+ t(
5310
+ "xapp.checkout_package_missing",
5311
+ void 0,
5312
+ "This package is missing purchase metadata in the published paywall."
5313
+ )
5314
+ );
5315
+ return;
5316
+ }
5317
+ setCheckoutBusyPackageSlug(normalizedSlug);
5318
+ setCheckoutError(null);
5319
+ setCheckoutNotice(null);
5320
+ try {
5321
+ const prepared = await client.prepareMyXappPurchaseIntent({
5322
+ xappId: String(xappId),
5323
+ offeringId,
5324
+ packageId,
5325
+ priceId,
5326
+ installationId: installation?.installationId ?? null
5327
+ });
5328
+ const returnUrl = buildMonetizationCheckoutReturnUrl({
5329
+ currentHref: window.location.href,
5330
+ intentId: String(prepared.prepared_intent.purchase_intent_id || ""),
5331
+ packageSlug: normalizedSlug
5332
+ });
5333
+ const payment = await client.createMyXappPurchasePaymentSession({
5334
+ xappId: String(xappId),
5335
+ intentId: String(prepared.prepared_intent.purchase_intent_id || ""),
5336
+ returnUrl,
5337
+ cancelUrl: returnUrl,
5338
+ xappsResume: returnUrl,
5339
+ locale
5340
+ });
5341
+ const paymentPageUrl = readString5(payment.payment_page_url);
5342
+ const paymentStatus = readString5(payment.payment_session?.status).trim().toLowerCase();
5343
+ if (!paymentPageUrl && (paymentStatus === "paid" || paymentStatus === "completed")) {
5344
+ await finalizeCurrentUserCheckoutIntent(
5345
+ String(xappId),
5346
+ String(prepared.prepared_intent.purchase_intent_id || "")
5347
+ );
5348
+ return;
5349
+ }
5350
+ if (!paymentPageUrl) {
5351
+ throw new Error(
5352
+ t(
5353
+ "xapp.checkout_page_missing",
5354
+ void 0,
5355
+ "Payment page is not available for this package."
5356
+ )
5357
+ );
5358
+ }
5359
+ navigateToHostedCheckout(paymentPageUrl);
5360
+ } catch (error2) {
5361
+ const message = readString5(asRecord6(error2)?.message) || (error2 instanceof Error ? error2.message : "") || t("xapp.checkout_start_failed", void 0, "Unable to start checkout for this package.");
5362
+ setCheckoutError(message);
5363
+ } finally {
5364
+ setCheckoutBusyPackageSlug("");
5365
+ }
5366
+ }
4665
5367
  const hasCatalogMonetization = hasMarketplaceCatalogMonetization(manifest);
4666
5368
  const monetizationAccess = asRecord6(monetization?.access_projection);
4667
5369
  const monetizationSubscription = asRecord6(monetization?.current_subscription);
5370
+ const additiveEntitlements = Array.isArray(monetization?.additive_entitlements) ? monetization.additive_entitlements.map((item) => asRecord6(item)).filter((item) => item ? Object.keys(item).length > 0 : false) : [];
5371
+ const activeAdditiveEntitlements = additiveEntitlements.filter((item) => {
5372
+ const status = readString5(item.status).trim().toLowerCase();
5373
+ return status === "active" || status === "grace_period";
5374
+ });
5375
+ const additiveUnlockLabels = activeAdditiveEntitlements.map((item) => readString5(item.tier) || readString5(item.product_slug)).filter(Boolean);
4668
5376
  const overduePolicy = asRecord6(monetizationSubscription?.overdue_policy);
4669
- const currentTier = readString4(monetizationSubscription?.tier) || readString4(monetizationAccess?.tier);
4670
- const balanceState = readString4(monetizationAccess?.balance_state);
4671
- const subscriptionStatus = readString4(monetizationSubscription?.status);
5377
+ const currentTier = readString5(monetizationSubscription?.tier) || readString5(monetizationAccess?.tier);
5378
+ const balanceState = readString5(monetizationAccess?.balance_state);
5379
+ const subscriptionStatus = readString5(monetizationSubscription?.status);
4672
5380
  const subscriptionCoverage = typeof overduePolicy?.has_current_access === "boolean" ? overduePolicy.has_current_access ? t("xapp.subscription_coverage_active", void 0, "Still covered") : t("xapp.subscription_coverage_inactive", void 0, "Not covered") : null;
4673
- const subscriptionReasonKey = readString4(overduePolicy?.effective_status_reason);
5381
+ const subscriptionReasonKey = readString5(overduePolicy?.effective_status_reason);
4674
5382
  const subscriptionReason = subscriptionReasonKey === "grace_covered_past_due" ? t(
4675
5383
  "xapp.subscription_reason_grace_covered_past_due",
4676
5384
  void 0,
@@ -4688,17 +5396,154 @@ function XappDetailPage() {
4688
5396
  const expiryBoundaryAt = formatDateTime2(overduePolicy?.expiry_boundary_at, locale);
4689
5397
  const renewsAt = formatDateTime2(monetizationSubscription?.renews_at, locale);
4690
5398
  const expiresAt = formatDateTime2(monetizationSubscription?.expired_at, locale) || formatDateTime2(monetizationSubscription?.current_period_ends_at, locale);
4691
- const creditsRemaining = readString4(monetizationAccess?.credits_remaining);
5399
+ const creditsRemaining = readString5(monetizationAccess?.credits_remaining);
4692
5400
  const accessState = resolveMarketplaceDefaultAccessState({
4693
5401
  projection: monetizationAccessProjection,
4694
5402
  hasCatalogMonetization,
4695
5403
  availableLabel: t("xapp.access_state_available", void 0, "available")
4696
5404
  });
4697
5405
  const hasMonetizationState = Boolean(
4698
- currentTier || accessState || subscriptionStatus || subscriptionCoverage || subscriptionReason || overdueSince || expiryBoundaryAt || renewsAt || expiresAt || creditsRemaining
5406
+ currentTier || accessState || subscriptionStatus || subscriptionCoverage || subscriptionReason || overdueSince || expiryBoundaryAt || renewsAt || expiresAt || creditsRemaining || additiveUnlockLabels.length > 0
4699
5407
  );
4700
- const manifestScreenshots = Array.isArray(manifest?.screenshots) ? manifest.screenshots.map((shot) => readString4(shot)).filter(Boolean) : [];
4701
- const manifestTags = Array.isArray(manifest?.tags) ? manifest.tags.map((tag) => readString4(tag)).filter(Boolean) : [];
5408
+ const manifestScreenshots = Array.isArray(manifest?.screenshots) ? manifest.screenshots.map((shot) => readString5(shot)).filter(Boolean) : [];
5409
+ const manifestTags = Array.isArray(manifest?.tags) ? manifest.tags.map((tag) => readString5(tag)).filter(Boolean) : [];
5410
+ function getPackagePurchasePolicy(item) {
5411
+ return resolveMonetizationPackagePurchasePolicy({
5412
+ item,
5413
+ currentSubscription: monetizationSubscription,
5414
+ additiveEntitlements: activeAdditiveEntitlements
5415
+ });
5416
+ }
5417
+ const currentAccessCard = hasMonetizationState ? /* @__PURE__ */ jsxs10("div", { className: "mx-sidebar-card", children: [
5418
+ /* @__PURE__ */ jsx14("h3", { className: "mx-section-title mx-detail-sidebar-title", children: t("xapp.current_access_title", void 0, "Current Access") }),
5419
+ currentTier ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5420
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.current_plan_label", void 0, "Current plan") }),
5421
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: currentTier })
5422
+ ] }) : null,
5423
+ accessState ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5424
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.access_state_label", void 0, "Access state") }),
5425
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: accessState })
5426
+ ] }) : null,
5427
+ subscriptionStatus ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5428
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.subscription_status_label", void 0, "Subscription status") }),
5429
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: subscriptionStatus })
5430
+ ] }) : null,
5431
+ subscriptionCoverage ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5432
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.subscription_coverage_label", void 0, "Coverage") }),
5433
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: subscriptionCoverage })
5434
+ ] }) : null,
5435
+ subscriptionReason ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item mx-meta-item-top", children: [
5436
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.subscription_reason_label", void 0, "Status reason") }),
5437
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: subscriptionReason })
5438
+ ] }) : null,
5439
+ overdueSince ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5440
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.subscription_overdue_since_label", void 0, "Overdue since") }),
5441
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: overdueSince })
5442
+ ] }) : null,
5443
+ expiryBoundaryAt ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5444
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.subscription_expiry_boundary_label", void 0, "Expiry boundary") }),
5445
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: expiryBoundaryAt })
5446
+ ] }) : null,
5447
+ renewsAt ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5448
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.renews_at_label", void 0, "Renews at") }),
5449
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: renewsAt })
5450
+ ] }) : null,
5451
+ expiresAt ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5452
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.expires_at_label", void 0, "Expires at") }),
5453
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: expiresAt })
5454
+ ] }) : null,
5455
+ creditsRemaining ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5456
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.credits_remaining_label", void 0, "Credits remaining") }),
5457
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: creditsRemaining })
5458
+ ] }) : null,
5459
+ additiveUnlockLabels.length > 0 ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item mx-meta-item-top", children: [
5460
+ /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.add_on_unlocks_label", void 0, "Add-on unlocks") }),
5461
+ /* @__PURE__ */ jsx14("div", { className: "mx-meta-value mx-meta-stack-sm", children: additiveUnlockLabels.map((label) => /* @__PURE__ */ jsx14("div", { children: label }, label)) })
5462
+ ] }) : null
5463
+ ] }) : null;
5464
+ const plansCard = selectedPaywallRenderModel ? /* @__PURE__ */ jsxs10("div", { className: "mx-sidebar-card", ref: plansSectionRef, children: [
5465
+ /* @__PURE__ */ jsx14("h3", { className: "mx-section-title mx-detail-sidebar-title", children: t("xapp.plan_options_title", void 0, "Plans") }),
5466
+ /* @__PURE__ */ jsxs10("div", { className: "mx-paywall-card-head", children: [
5467
+ /* @__PURE__ */ jsx14("div", { className: "mx-paywall-card-title", children: selectedPaywallRenderModel.paywallLabel }),
5468
+ selectedPaywallRenderModel.summary ? /* @__PURE__ */ jsx14("div", { className: "mx-paywall-card-summary", children: selectedPaywallRenderModel.summary }) : null
5469
+ ] }),
5470
+ selectedPaywallRenderModel.badges.length > 0 ? /* @__PURE__ */ jsx14("div", { className: "mx-paywall-card-badges", children: selectedPaywallRenderModel.badges.map((badge) => /* @__PURE__ */ jsx14("span", { className: "mx-paywall-card-badge", children: badge }, badge)) }) : null,
5471
+ /* @__PURE__ */ jsx14("div", { className: "mx-paywall-card-packages", children: selectedPaywallRenderModel.packages.map((item) => {
5472
+ const normalizedPackageSlug = item.packageSlug.trim().toLowerCase();
5473
+ const purchasePolicy = getPackagePurchasePolicy(item);
5474
+ const isCurrentPackage = purchasePolicy.status === "current_recurring_plan";
5475
+ const isOwnedAdditive = purchasePolicy.status === "owned_additive_unlock";
5476
+ const isAdditiveCompanion = purchasePolicy.transitionKind === "buy_additive_unlock" && subscriptionStatus === "active";
5477
+ return /* @__PURE__ */ jsxs10(
5478
+ "div",
5479
+ {
5480
+ className: `mx-paywall-card-package ${item.isDefault ? "is-default" : ""} ${selectedPaywallPackageSlug && normalizedPackageSlug === selectedPaywallPackageSlug ? "is-selected" : ""}`,
5481
+ children: [
5482
+ /* @__PURE__ */ jsxs10("div", { className: "mx-paywall-card-package-head", children: [
5483
+ /* @__PURE__ */ jsxs10("div", { children: [
5484
+ /* @__PURE__ */ jsx14("div", { className: "mx-paywall-card-package-title", children: item.packageTitle }),
5485
+ item.description ? /* @__PURE__ */ jsx14("div", { className: "mx-paywall-card-package-description", children: item.description }) : null
5486
+ ] }),
5487
+ /* @__PURE__ */ jsx14("div", { className: "mx-paywall-card-money", children: item.moneyLabel })
5488
+ ] }),
5489
+ /* @__PURE__ */ jsxs10("div", { className: "mx-paywall-card-package-meta", children: [
5490
+ /* @__PURE__ */ jsx14("span", { className: "mx-paywall-card-package-fit", children: item.fitLabel }),
5491
+ selectedPaywallPackageSlug && normalizedPackageSlug === selectedPaywallPackageSlug ? /* @__PURE__ */ jsx14("span", { className: "mx-paywall-card-package-default", children: t("xapp.selected_label", void 0, "Selected") }) : null,
5492
+ isOwnedAdditive ? /* @__PURE__ */ jsx14("span", { className: "mx-paywall-card-package-default", children: t("xapp.owned_unlock_label", void 0, "Owned unlock") }) : null,
5493
+ isCurrentPackage && !isOwnedAdditive ? /* @__PURE__ */ jsx14("span", { className: "mx-paywall-card-package-default", children: t("xapp.current_plan_label", void 0, "Current plan") }) : null,
5494
+ isAdditiveCompanion ? /* @__PURE__ */ jsx14("span", { className: "mx-paywall-card-package-default", children: t("xapp.additive_unlock_label", void 0, "Add-on with membership") }) : null,
5495
+ item.isDefault ? /* @__PURE__ */ jsx14("span", { className: "mx-paywall-card-package-default", children: t("xapp.default_label", void 0, "Default") }) : null
5496
+ ] }),
5497
+ item.signals.length > 0 ? /* @__PURE__ */ jsx14("div", { className: "mx-paywall-card-signals", children: item.signals.map((signal) => /* @__PURE__ */ jsx14("span", { className: "mx-paywall-card-signal", children: signal }, signal)) }) : null,
5498
+ isAdditiveCompanion ? /* @__PURE__ */ jsx14("div", { className: "mx-paywall-card-summary", children: t(
5499
+ "xapp.additive_unlock_message",
5500
+ void 0,
5501
+ "This one-time unlock is additive. It adds access on top of the active recurring membership instead of replacing it."
5502
+ ) }) : null,
5503
+ typeof client.prepareMyXappPurchaseIntent === "function" && typeof client.createMyXappPurchasePaymentSession === "function" && canMutate ? /* @__PURE__ */ jsx14(
5504
+ "button",
5505
+ {
5506
+ className: "mx-btn mx-btn-secondary",
5507
+ disabled: !purchasePolicy.canPurchase || checkoutBusyPackageSlug === normalizedPackageSlug,
5508
+ onClick: () => void startPackageCheckout(item.packageSlug),
5509
+ children: isOwnedAdditive ? t("xapp.owned_unlock_active", void 0, "Owned unlock active") : isCurrentPackage ? t("xapp.current_plan_active", void 0, "Current plan active") : checkoutBusyPackageSlug === normalizedPackageSlug ? t("xapp.checkout_starting", void 0, "Starting checkout...") : isAdditiveCompanion ? t("xapp.additive_unlock_action", void 0, "Purchase add-on unlock") : t("xapp.checkout_action", void 0, "Continue to checkout")
5510
+ }
5511
+ ) : null
5512
+ ]
5513
+ },
5514
+ item.packageId || item.packageSlug
5515
+ );
5516
+ }) }),
5517
+ checkoutNotice ? /* @__PURE__ */ jsx14("div", { className: "mx-paywall-card-summary", children: checkoutNotice }) : null,
5518
+ checkoutError ? /* @__PURE__ */ jsx14("div", { className: "mx-payment-lock-error", children: checkoutError }) : null
5519
+ ] }) : null;
5520
+ if (plansOnlyMode) {
5521
+ return /* @__PURE__ */ jsxs10("div", { className: `mx-detail-container ${isEmbedded ? "is-embedded" : ""}`, children: [
5522
+ error && /* @__PURE__ */ jsx14("div", { className: "mx-detail-error", children: error }),
5523
+ busy && !data ? /* @__PURE__ */ jsx14("div", { className: "mx-sidebar-card mx-detail-empty", "aria-busy": "true", children: t("common.loading", void 0, "Loading...") }) : /* @__PURE__ */ jsxs10("div", { className: `mx-plans-route ${widgetHostedPlansMode ? "is-widget-hosted" : ""}`, children: [
5524
+ !widgetHostedPlansMode ? /* @__PURE__ */ jsxs10("div", { className: "mx-plans-route-header", children: [
5525
+ /* @__PURE__ */ jsx14("div", { className: "mx-plans-route-title", children: t("xapp.plan_options_title", void 0, "Plans") }),
5526
+ /* @__PURE__ */ jsx14("div", { className: "mx-plans-route-subtitle", children: title ? t(
5527
+ "xapp.plans_route_subtitle",
5528
+ { title },
5529
+ `Current access and published plans for ${title}.`
5530
+ ) : t(
5531
+ "xapp.plans_route_subtitle_default",
5532
+ void 0,
5533
+ "Current access and published plans for this app."
5534
+ ) })
5535
+ ] }) : null,
5536
+ /* @__PURE__ */ jsx14("div", { className: "mx-plans-route-grid", children: /* @__PURE__ */ jsxs10("div", { className: "mx-plans-route-main", children: [
5537
+ currentAccessCard,
5538
+ plansCard || /* @__PURE__ */ jsx14("div", { className: "mx-sidebar-card mx-detail-empty", children: t(
5539
+ "xapp.no_plans_available",
5540
+ void 0,
5541
+ "No published plans are currently available."
5542
+ ) })
5543
+ ] }) })
5544
+ ] })
5545
+ ] });
5546
+ }
4702
5547
  return /* @__PURE__ */ jsxs10("div", { className: `mx-detail-container ${isEmbedded ? "is-embedded" : ""}`, children: [
4703
5548
  /* @__PURE__ */ jsxs10("div", { className: "mx-detail-topbar", children: [
4704
5549
  /* @__PURE__ */ jsxs10("div", { className: "mx-detail-topbar-left", children: [
@@ -4778,9 +5623,9 @@ function XappDetailPage() {
4778
5623
  description ? /* @__PURE__ */ jsx14("p", { className: "mx-detail-subtitle", children: description }) : null,
4779
5624
  /* @__PURE__ */ jsxs10("div", { className: "mx-detail-meta-row", children: [
4780
5625
  /* @__PURE__ */ jsx14("div", { className: "mx-card-slug", children: xappId }),
4781
- readString4(versionRecord?.version) && /* @__PURE__ */ jsxs10("div", { className: "mx-card-version mx-detail-version-pill", children: [
5626
+ readString5(versionRecord?.version) && /* @__PURE__ */ jsxs10("div", { className: "mx-card-version mx-detail-version-pill", children: [
4782
5627
  "v",
4783
- readString4(versionRecord?.version)
5628
+ readString5(versionRecord?.version)
4784
5629
  ] }),
4785
5630
  updateAvailable ? /* @__PURE__ */ jsx14("div", { className: "mx-detail-update-pill", children: t("xapp.update_available", void 0, "Update available") }) : null
4786
5631
  ] })
@@ -4821,7 +5666,7 @@ function XappDetailPage() {
4821
5666
  }
4822
5667
  host.requestInstall({
4823
5668
  xappId: String(xappId ?? ""),
4824
- defaultWidgetId: readString4(defaultWidget?.id) || null,
5669
+ defaultWidgetId: readString5(defaultWidget?.id) || null,
4825
5670
  subjectId: host.subjectId ?? null
4826
5671
  });
4827
5672
  },
@@ -4867,9 +5712,9 @@ function XappDetailPage() {
4867
5712
  void 0,
4868
5713
  "No app views are currently available."
4869
5714
  ) }) : /* @__PURE__ */ jsx14("div", { className: "mx-detail-widget-list", children: widgets.map((w, idx) => {
4870
- const name = resolveMarketplaceText(w.title, locale) || readString4(w.widget_name) || readString4(w.name) || readString4(w.id) || t("common.widget", void 0, "Widget");
5715
+ const name = resolveMarketplaceText(w.title, locale) || readString5(w.widget_name) || readString5(w.name) || readString5(w.id) || t("common.widget", void 0, "Widget");
4871
5716
  const disabled = !widgetsEnabled;
4872
- const isDefault = readBoolean(w.default, false) || idx === 0 && !widgets.some((ww) => readBoolean(ww.default, false));
5717
+ const isDefault = readBoolean2(w.default, false) || idx === 0 && !widgets.some((ww) => readBoolean2(ww.default, false));
4873
5718
  const widgetType = String(w.type || "").toLowerCase();
4874
5719
  return /* @__PURE__ */ jsxs10(
4875
5720
  "button",
@@ -4878,7 +5723,7 @@ function XappDetailPage() {
4878
5723
  className: `mx-detail-widget-card ${disabled ? "is-disabled" : ""} ${isDefault ? "is-default" : ""}`,
4879
5724
  onClick: () => {
4880
5725
  if (!installation || !widgetsEnabled) return;
4881
- const widgetId = readString4(w.id);
5726
+ const widgetId = readString5(w.id);
4882
5727
  if (!widgetId) return;
4883
5728
  if (env?.embedMode && installation) {
4884
5729
  navigate({
@@ -4893,7 +5738,7 @@ function XappDetailPage() {
4893
5738
  xappId: String(xappId ?? ""),
4894
5739
  xappTitle: String(title),
4895
5740
  widgetName: name,
4896
- toolName: readString4(w.bind_tool_name)
5741
+ toolName: readString5(w.bind_tool_name)
4897
5742
  });
4898
5743
  },
4899
5744
  children: [
@@ -4929,7 +5774,7 @@ function XappDetailPage() {
4929
5774
  ) }),
4930
5775
  /* @__PURE__ */ jsxs10("div", { className: "mx-detail-widget-body", children: [
4931
5776
  /* @__PURE__ */ jsx14("div", { className: "mx-detail-widget-name", children: name }),
4932
- readString4(w.bind_tool_name) && /* @__PURE__ */ jsx14("div", { className: "mx-detail-widget-tool", children: readString4(w.bind_tool_name) }),
5777
+ readString5(w.bind_tool_name) && /* @__PURE__ */ jsx14("div", { className: "mx-detail-widget-tool", children: readString5(w.bind_tool_name) }),
4933
5778
  /* @__PURE__ */ jsxs10("div", { className: "mx-detail-widget-badges", children: [
4934
5779
  isDefault && /* @__PURE__ */ jsx14("span", { className: "mx-detail-widget-badge is-primary", children: t("xapp.widget_primary", void 0, "Primary") }),
4935
5780
  widgetType && /* @__PURE__ */ jsx14("span", { className: "mx-detail-widget-badge", children: widgetType })
@@ -5062,7 +5907,14 @@ function XappDetailPage() {
5062
5907
  children: [
5063
5908
  /* @__PURE__ */ jsxs10("div", { className: "mx-guard-row-left", children: [
5064
5909
  guard.order !== null ? /* @__PURE__ */ jsx14("span", { className: "mx-guard-row-order", children: guard.order }) : /* @__PURE__ */ jsx14("span", { className: "mx-guard-row-order", children: guardIdx + 1 }),
5065
- /* @__PURE__ */ jsx14("span", { className: "mx-guard-row-name", title: guard.slug, children: humanizeSlug(guard.slug) })
5910
+ /* @__PURE__ */ jsx14(
5911
+ "span",
5912
+ {
5913
+ className: "mx-guard-row-name",
5914
+ title: guard.label || guard.slug,
5915
+ children: guard.label ? guard.label : humanizeSlug(guard.slug)
5916
+ }
5917
+ )
5066
5918
  ] }),
5067
5919
  /* @__PURE__ */ jsxs10("div", { className: "mx-guard-row-right", children: [
5068
5920
  /* @__PURE__ */ jsxs10(
@@ -5145,49 +5997,7 @@ function XappDetailPage() {
5145
5997
  ] })
5146
5998
  ] }),
5147
5999
  /* @__PURE__ */ jsxs10("aside", { className: "mx-detail-sidebar", children: [
5148
- hasMonetizationState ? /* @__PURE__ */ jsxs10("div", { className: "mx-sidebar-card", children: [
5149
- /* @__PURE__ */ jsx14("h3", { className: "mx-section-title mx-detail-sidebar-title", children: t("xapp.current_access_title", void 0, "Current Access") }),
5150
- currentTier ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5151
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.current_plan_label", void 0, "Current plan") }),
5152
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: currentTier })
5153
- ] }) : null,
5154
- accessState ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5155
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.access_state_label", void 0, "Access state") }),
5156
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: accessState })
5157
- ] }) : null,
5158
- subscriptionStatus ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5159
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.subscription_status_label", void 0, "Subscription status") }),
5160
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: subscriptionStatus })
5161
- ] }) : null,
5162
- subscriptionCoverage ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5163
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.subscription_coverage_label", void 0, "Coverage") }),
5164
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: subscriptionCoverage })
5165
- ] }) : null,
5166
- subscriptionReason ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item mx-meta-item-top", children: [
5167
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.subscription_reason_label", void 0, "Status reason") }),
5168
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: subscriptionReason })
5169
- ] }) : null,
5170
- overdueSince ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5171
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.subscription_overdue_since_label", void 0, "Overdue since") }),
5172
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: overdueSince })
5173
- ] }) : null,
5174
- expiryBoundaryAt ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5175
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.subscription_expiry_boundary_label", void 0, "Expiry boundary") }),
5176
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: expiryBoundaryAt })
5177
- ] }) : null,
5178
- renewsAt ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5179
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.renews_at_label", void 0, "Renews at") }),
5180
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: renewsAt })
5181
- ] }) : null,
5182
- expiresAt ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5183
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.expires_at_label", void 0, "Expires at") }),
5184
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: expiresAt })
5185
- ] }) : null,
5186
- creditsRemaining ? /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
5187
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-label", children: t("xapp.credits_remaining_label", void 0, "Credits remaining") }),
5188
- /* @__PURE__ */ jsx14("span", { className: "mx-meta-value", children: creditsRemaining })
5189
- ] }) : null
5190
- ] }) : null,
6000
+ currentAccessCard,
5191
6001
  usageCreditSummary ? /* @__PURE__ */ jsxs10("div", { className: "mx-sidebar-card", children: [
5192
6002
  /* @__PURE__ */ jsx14("h3", { className: "mx-section-title mx-detail-sidebar-title", children: t("xapp.usage_credits_title", void 0, "Usage Credits") }),
5193
6003
  /* @__PURE__ */ jsxs10("div", { className: "mx-meta-item", children: [
@@ -5248,6 +6058,7 @@ function XappDetailPage() {
5248
6058
  ] }, tool.tool_name)) })
5249
6059
  ] }) : null
5250
6060
  ] }) : null,
6061
+ plansCard,
5251
6062
  installation && defaultWidget && hasSubject && /* @__PURE__ */ jsx14(
5252
6063
  "button",
5253
6064
  {
@@ -5262,11 +6073,11 @@ function XappDetailPage() {
5262
6073
  }
5263
6074
  host.openWidget({
5264
6075
  installationId: installation.installationId,
5265
- widgetId: readString4(defaultWidget.id),
6076
+ widgetId: readString5(defaultWidget.id),
5266
6077
  xappId: String(xappId ?? ""),
5267
6078
  xappTitle: String(title),
5268
- widgetName: resolveMarketplaceText(defaultWidget?.title, locale) || readString4(defaultWidget?.widget_name) || readString4(defaultWidget?.name) || t("common.widget", void 0, "Widget"),
5269
- toolName: readString4(defaultWidget?.bind_tool_name)
6079
+ widgetName: resolveMarketplaceText(defaultWidget?.title, locale) || readString5(defaultWidget?.widget_name) || readString5(defaultWidget?.name) || t("common.widget", void 0, "Widget"),
6080
+ toolName: readString5(defaultWidget?.bind_tool_name)
5270
6081
  });
5271
6082
  },
5272
6083
  children: openAppLabel
@@ -5457,7 +6268,7 @@ function XappDetailPage() {
5457
6268
  onClick: () => {
5458
6269
  host.requestInstall({
5459
6270
  xappId: String(xappId ?? ""),
5460
- defaultWidgetId: readString4(defaultWidget?.id) || null,
6271
+ defaultWidgetId: readString5(defaultWidget?.id) || null,
5461
6272
  subjectId: host.subjectId ?? null,
5462
6273
  termsAccepted: true
5463
6274
  });
@@ -6741,6 +7552,7 @@ function MarketplaceApp() {
6741
7552
  /* @__PURE__ */ jsx18(Route, { path: "publishers", element: /* @__PURE__ */ jsx18(PublishersPage, {}) }),
6742
7553
  /* @__PURE__ */ jsx18(Route, { path: "publishers/:publisherSlug", element: /* @__PURE__ */ jsx18(PublisherDetailPage, {}) }),
6743
7554
  /* @__PURE__ */ jsx18(Route, { path: "xapps/:xappId", element: /* @__PURE__ */ jsx18(XappDetailPage, {}) }),
7555
+ /* @__PURE__ */ jsx18(Route, { path: "xapps/:xappId/plans", element: /* @__PURE__ */ jsx18(XappPlansPage, {}) }),
6744
7556
  /* @__PURE__ */ jsx18(Route, { path: "requests", element: /* @__PURE__ */ jsx18(RequestsPage, {}) }),
6745
7557
  /* @__PURE__ */ jsx18(Route, { path: "payments", element: /* @__PURE__ */ jsx18(PaymentsPage, {}) }),
6746
7558
  /* @__PURE__ */ jsx18(Route, { path: "invoices", element: /* @__PURE__ */ jsx18(InvoicesPage, {}) }),
@@ -6761,6 +7573,7 @@ export {
6761
7573
  RequestsPage,
6762
7574
  WidgetView,
6763
7575
  XappDetailPage,
7576
+ XappPlansPage,
6764
7577
  resolveMarketplaceText,
6765
7578
  resolvePaymentLockStateFromGuardSummary,
6766
7579
  useMarketplace,