@xapps-platform/marketplace-ui 0.1.14 → 0.1.16

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
@@ -106,6 +106,120 @@ function useI18n() {
106
106
 
107
107
  // src/i18n.tsx
108
108
  import { jsx as jsx2 } from "react/jsx-runtime";
109
+ function buildMarketplaceXmsCatalog(locale) {
110
+ if (locale === "ro") {
111
+ return {
112
+ "xapp.current_plan_label": "Plan curent",
113
+ "xapp.selected_label": "Selectat",
114
+ "xapp.default_label": "Implicit",
115
+ "xapp.owned_unlock_label": "Unlock de\u021Binut",
116
+ "xapp.additive_unlock_label": "Supliment cu abonament",
117
+ "xapp.owned_unlock_active": "Unlock deja activ",
118
+ "xapp.current_plan_active": "Plan activ",
119
+ "xapp.checkout_starting": "Se porne\u0219te checkout-ul...",
120
+ "xapp.additive_unlock_action": "Cump\u0103r\u0103 suplimentul",
121
+ "xapp.checkout_action": "\xCEncepe checkout-ul",
122
+ "xapp.subscription_status_label": "Stare abonament",
123
+ "xapp.subscription_coverage_label": "Acoperire",
124
+ "xapp.subscription_reason_label": "Motiv stare",
125
+ "xapp.subscription_overdue_since_label": "Restant din",
126
+ "xapp.subscription_expiry_boundary_label": "Limit\u0103 expirare",
127
+ "xapp.current_period_ends_label": "Perioada curent\u0103 se \xEEncheie la",
128
+ "xapp.cancelled_at_label": "Anulat la",
129
+ "xapp.virtual_currency_label": "Moned\u0103 virtual\u0103",
130
+ "xapp.current_balances_label": "Solduri acum",
131
+ "xapp.credits_remaining_label": "Sold",
132
+ "xapp.add_on_unlocks_label": "Unlock-uri suplimentare",
133
+ "xapp.subscription_refresh_action": "Actualizeaz\u0103 starea",
134
+ "xapp.subscription_refreshing": "Se actualizeaz\u0103...",
135
+ "xapp.subscription_cancel_action": "Anuleaz\u0103 abonamentul",
136
+ "xapp.subscription_cancelling": "Se anuleaz\u0103...",
137
+ "xapp.subscription_operator_authority_label": "Autoritate operator",
138
+ "xapp.subscription_management_destination_label": "Administreaz\u0103 \xEEn",
139
+ "xapp.subscription_operator_authority_gateway": "Gateway",
140
+ "xapp.subscription_operator_authority_tenant": "Tenant",
141
+ "xapp.subscription_operator_authority_publisher": "Publisher",
142
+ "xapp.subscription_operator_authority_owner": "Proprietar aplica\u021Bie",
143
+ "xapp.subscription_management_destination_gateway": "Administrare gateway",
144
+ "xapp.subscription_management_destination_tenant": "Aplica\u021Bia tenantului",
145
+ "xapp.subscription_management_destination_publisher": "Aplica\u021Bia publisherului",
146
+ "xapp.subscription_management_destination_owner": "Proprietarul aplica\u021Biei",
147
+ "xapp.subscription_management_hint_gateway": "Administrarea avansat\u0103 a abonamentului se face \xEEn administrarea gateway-ului.",
148
+ "xapp.subscription_management_hint_tenant": "Administrarea avansat\u0103 a abonamentului se face \xEEn aplica\u021Bia tenantului.",
149
+ "xapp.subscription_management_hint_publisher": "Administrarea avansat\u0103 a abonamentului se face \xEEn aplica\u021Bia publisherului.",
150
+ "xapp.subscription_management_hint_owner": "Administrarea avansat\u0103 a abonamentului este gestionat\u0103 de proprietarul aplica\u021Biei.",
151
+ "xapp.subscription_management_open_action": "Deschide administrarea",
152
+ "xapp.lifecycle_preview_at_label": "Previzualizare la",
153
+ "xapp.lifecycle_preview_hint": "Starea abonamentului este previzualizat\u0103 pentru momentul selectat.",
154
+ "xapp.history_route_subtitle": "Solduri, activitate recent\u0103 \u0219i cump\u0103r\u0103ri pentru {title}.",
155
+ "xapp.history_route_subtitle_default": "Solduri, activitate recent\u0103 \u0219i cump\u0103r\u0103ri pentru aceast\u0103 aplica\u021Bie.",
156
+ "xapp.plans_route_subtitle": "Acces, planuri \u0219i solduri pentru {title}.",
157
+ "xapp.plans_route_subtitle_default": "Acces, planuri \u0219i solduri pentru aceast\u0103 aplica\u021Bie.",
158
+ "xapp.plans_loading_title": "Se \xEEncarc\u0103 planurile",
159
+ "xapp.plans_loading_desc": "Se preg\u0103tesc planurile publicate, soldurile \u0219i accesul curent pentru aceast\u0103 aplica\u021Bie.",
160
+ "xapp.no_plans_available": "Momentan nu exist\u0103 planuri disponibile.",
161
+ "xapp.no_plans_available_desc": "Planurile publicate vor ap\u0103rea aici atunci c\xE2nd aceast\u0103 aplica\u021Bie expune un paywall.",
162
+ "xapp.checkout_hint": "Checkout-ul se deschide \xEEntr-o pagin\u0103 securizat\u0103 de plat\u0103 administrat\u0103 de platform\u0103.",
163
+ "xapp.current_plan_note": "Acest plan este deja activ pentru aceast\u0103 aplica\u021Bie.",
164
+ "xapp.owned_unlock_note": "Acest supliment este deja inclus \xEEn accesul curent."
165
+ };
166
+ }
167
+ return {
168
+ "xapp.current_plan_label": "Current plan",
169
+ "xapp.selected_label": "Selected",
170
+ "xapp.default_label": "Default",
171
+ "xapp.owned_unlock_label": "Owned unlock",
172
+ "xapp.additive_unlock_label": "Add-on with membership",
173
+ "xapp.owned_unlock_active": "Owned unlock active",
174
+ "xapp.current_plan_active": "Current plan active",
175
+ "xapp.checkout_starting": "Starting checkout...",
176
+ "xapp.additive_unlock_action": "Purchase add-on unlock",
177
+ "xapp.checkout_action": "Start checkout",
178
+ "xapp.subscription_status_label": "Subscription state",
179
+ "xapp.subscription_coverage_label": "Coverage",
180
+ "xapp.subscription_reason_label": "Status reason",
181
+ "xapp.subscription_overdue_since_label": "Overdue since",
182
+ "xapp.subscription_expiry_boundary_label": "Expiry boundary",
183
+ "xapp.current_period_ends_label": "Current period ends",
184
+ "xapp.cancelled_at_label": "Cancelled at",
185
+ "xapp.virtual_currency_label": "Currency",
186
+ "xapp.current_balances_label": "Balances now",
187
+ "xapp.credits_remaining_label": "Balance",
188
+ "xapp.add_on_unlocks_label": "Add-on unlocks",
189
+ "xapp.subscription_refresh_action": "Refresh status",
190
+ "xapp.subscription_refreshing": "Refreshing...",
191
+ "xapp.subscription_cancel_action": "Cancel subscription",
192
+ "xapp.subscription_cancelling": "Cancelling...",
193
+ "xapp.subscription_operator_authority_label": "Operator authority",
194
+ "xapp.subscription_management_destination_label": "Manage in",
195
+ "xapp.subscription_operator_authority_gateway": "Gateway",
196
+ "xapp.subscription_operator_authority_tenant": "Tenant",
197
+ "xapp.subscription_operator_authority_publisher": "Publisher",
198
+ "xapp.subscription_operator_authority_owner": "App owner",
199
+ "xapp.subscription_management_destination_gateway": "Gateway admin",
200
+ "xapp.subscription_management_destination_tenant": "Tenant app",
201
+ "xapp.subscription_management_destination_publisher": "Publisher app",
202
+ "xapp.subscription_management_destination_owner": "App owner",
203
+ "xapp.subscription_management_hint_gateway": "Advanced subscription management is handled in Gateway admin.",
204
+ "xapp.subscription_management_hint_tenant": "Advanced subscription management is handled in the tenant app.",
205
+ "xapp.subscription_management_hint_publisher": "Advanced subscription management is handled in the publisher app.",
206
+ "xapp.subscription_management_hint_owner": "Advanced subscription management is handled by the app owner.",
207
+ "xapp.subscription_management_open_action": "Open management",
208
+ "xapp.lifecycle_preview_at_label": "Preview as of",
209
+ "xapp.lifecycle_preview_hint": "Subscription state is being previewed for the selected time.",
210
+ "xapp.history_route_subtitle": "Balances, recent activity, and purchases for {title}.",
211
+ "xapp.history_route_subtitle_default": "Balances, recent activity, and purchases for this app.",
212
+ "xapp.plans_route_subtitle": "Access, plans, and balances for {title}.",
213
+ "xapp.plans_route_subtitle_default": "Access, plans, and balances for this app.",
214
+ "xapp.plans_loading_title": "Loading plans",
215
+ "xapp.plans_loading_desc": "Preparing published plans, balances, and current access for this app.",
216
+ "xapp.no_plans_available": "No plans are currently available.",
217
+ "xapp.no_plans_available_desc": "Published plans will appear here when this app exposes a paywall.",
218
+ "xapp.checkout_hint": "Checkout opens in a secure hosted payment page managed by the platform.",
219
+ "xapp.current_plan_note": "This plan is already active for this app.",
220
+ "xapp.owned_unlock_note": "This add-on is already included in the current access."
221
+ };
222
+ }
109
223
  var MARKETPLACE_CATALOGS = {
110
224
  en: {
111
225
  "common.id": "ID",
@@ -192,7 +306,7 @@ var MARKETPLACE_CATALOGS = {
192
306
  "activity.invoices_title": "Invoices",
193
307
  "activity.notifications_title": "Notifications",
194
308
  "activity.unavailable_requests_title": "Requests are unavailable",
195
- "activity.unavailable_monetization_title": "Monetization is unavailable in this host.",
309
+ "activity.unavailable_monetization_title": "Plans and balances are unavailable in this host.",
196
310
  "activity.unavailable_requests_desc": "This public catalog does not support viewing personal requests.",
197
311
  "activity.unavailable_payments_title": "Payments are unavailable in this host.",
198
312
  "activity.unavailable_invoices_title": "Invoices are unavailable in this host.",
@@ -201,8 +315,8 @@ var MARKETPLACE_CATALOGS = {
201
315
  "activity.subject_required_desc": "This host session is not associated with a user. Ask your host to create a catalog session with a subjectId.",
202
316
  "activity.showing_requests_for": "Showing requests for {title}",
203
317
  "activity.showing_requests_for_prefix": "Showing requests for",
204
- "activity.showing_monetization_for": "Showing XMS state for {title}",
205
- "activity.showing_monetization_for_prefix": "Showing XMS state for",
318
+ "activity.showing_monetization_for": "Showing plans and balances for {title}",
319
+ "activity.showing_monetization_for_prefix": "Showing plans and balances for",
206
320
  "activity.showing_payments_for": "Showing payment activity for {title}",
207
321
  "activity.showing_payments_for_prefix": "Showing payment activity for",
208
322
  "activity.showing_invoices_for": "Showing invoice records for {title}",
@@ -218,11 +332,11 @@ var MARKETPLACE_CATALOGS = {
218
332
  "activity.mark_read": "Mark read",
219
333
  "activity.unread_count": "{count} unread item{suffix}",
220
334
  "activity.loading_requests": "Loading requests...",
221
- "activity.loading_monetization": "Loading monetization state...",
335
+ "activity.loading_monetization": "Loading plans, balances, and recent activity...",
222
336
  "activity.no_requests": "No requests yet.",
223
- "activity.no_monetization": "No XMS-enabled apps are currently installed for this subject.",
224
- "activity.no_monetization_current": "No current monetization coverage was found for this subject.",
225
- "activity.no_monetization_history": "No monetization history was found for this subject.",
337
+ "activity.no_monetization": "No monetized apps are currently installed for this subject.",
338
+ "activity.no_monetization_current": "No current plans or balances were found for this subject.",
339
+ "activity.no_monetization_history": "No plan or balance history was found for this subject.",
226
340
  "activity.loading_payments": "Loading payments...",
227
341
  "activity.no_payments": "No payment activity found.",
228
342
  "activity.loading_payment_detail": "Loading payment details...",
@@ -237,21 +351,30 @@ var MARKETPLACE_CATALOGS = {
237
351
  "activity.loading_notifications": "Loading notifications...",
238
352
  "activity.no_notifications": "No notification activity found.",
239
353
  "activity.loading_notification_detail": "Loading notification details...",
240
- "activity.monetization_overview_hint": "Review current XMS access, subscriptions, and credits across the apps linked to this subject.",
241
- "activity.monetization_overview_hint_with_past": "Review current and past XMS access, subscriptions, and credits across this subject's apps.",
242
- "activity.monetization_card_subtitle": "Current XMS state, active access, subscriptions, and credits for this app.",
243
- "activity.monetization_focus_xapp": "Focus this app",
244
- "activity.monetization_show_past": "Show past apps",
245
- "activity.monetization_show_current_only": "Show current only",
246
- "activity.monetization_open_plans": "Open plans",
247
- "activity.monetization_access_label": "Current access",
248
- "activity.monetization_plan_label": "Current plan",
249
- "activity.monetization_credits_label": "Credits remaining",
354
+ "activity.monetization_overview_hint": "Review current plans, subscriptions, and balances across this subject's apps.",
355
+ "activity.monetization_overview_hint_with_past": "Review current and past plans, subscriptions, and balances across this subject's apps.",
356
+ "activity.monetization_summary_title": "Plans and balances",
357
+ "activity.monetization_summary_subtitle": "Review active plans, subscriptions, and balances before opening app details or history.",
358
+ "activity.monetization_summary_apps": "Apps",
359
+ "activity.monetization_summary_subscriptions": "Subscriptions",
360
+ "activity.monetization_summary_balances": "Balances",
361
+ "activity.monetization_summary_currencies": "Named currencies",
362
+ "activity.monetization_card_subtitle": "Current plans, balances, and subscription state for this app.",
363
+ "activity.monetization_focus_xapp": "Only this app",
364
+ "activity.monetization_show_past": "Include past apps",
365
+ "activity.monetization_show_current_only": "Only current apps",
366
+ "activity.monetization_open_plans": "View plans",
367
+ "activity.monetization_open_history": "View history",
368
+ "activity.monetization_access_label": "Access",
369
+ "activity.monetization_plan_label": "Plan",
370
+ "activity.monetization_credits_label": "Balance",
250
371
  "activity.monetization_subscription_label": "Subscription",
251
- "activity.monetization_coverage_label": "Coverage",
372
+ "activity.monetization_coverage_label": "Renewal state",
252
373
  "activity.monetization_renews_at": "Renews at",
253
- "activity.monetization_balance_state": "Balance state",
254
- "activity.monetization_source_label": "Source",
374
+ "activity.monetization_balance_state": "Balance status",
375
+ "activity.monetization_balances_label": "Balances",
376
+ "activity.monetization_source_label": "Origin",
377
+ "activity.monetization_no_currency": "No named currency",
255
378
  "activity.monetization_unknown": "Unknown",
256
379
  "activity.monetization_none": "None",
257
380
  "activity.monetization_no_source": "No source",
@@ -301,6 +424,7 @@ var MARKETPLACE_CATALOGS = {
301
424
  "activity.guard_action_confirm_action": "Confirm action",
302
425
  "activity.guard_action_confirm_action_message": "Confirm action ({message})",
303
426
  "activity.guard_action_custom": "Action: {kind}",
427
+ ...buildMarketplaceXmsCatalog("en"),
304
428
  "status.unread": "Unread",
305
429
  "status.read": "Read",
306
430
  "common.back": "Back",
@@ -326,7 +450,9 @@ var MARKETPLACE_CATALOGS = {
326
450
  "xapp.update_available": "Update available",
327
451
  "xapp.about_title": "About",
328
452
  "xapp.available_views_title": "Available Views",
453
+ "xapp.open_to_access_views": "Open this app to start and install it automatically for your workspace.",
329
454
  "xapp.add_to_access_views": "Add this app to your workspace to access its available views.",
455
+ "xapp.update_to_access_views_auto": "Open a view to update the app automatically for your workspace.",
330
456
  "xapp.update_to_access_views": "An update is available. Please update the app to access its available views.",
331
457
  "xapp.load_as_user_to_access": "Load the catalog as a user to access this app.",
332
458
  "xapp.no_views_available": "No app views are currently available.",
@@ -350,20 +476,10 @@ var MARKETPLACE_CATALOGS = {
350
476
  "xapp.screenshots_title": "Screenshots",
351
477
  "xapp.screenshot_alt": "Screenshot {index}",
352
478
  "xapp.usage_credits_title": "Usage Credits",
353
- "xapp.current_access_title": "Current Access",
354
- "xapp.current_plan_label": "Current plan",
355
- "xapp.selected_label": "Selected",
356
- "xapp.default_label": "Default",
357
- "xapp.owned_unlock_label": "Owned unlock",
358
- "xapp.additive_unlock_label": "Add-on with membership",
359
- "xapp.owned_unlock_active": "Owned unlock active",
360
- "xapp.current_plan_active": "Current plan active",
361
- "xapp.checkout_starting": "Starting checkout...",
362
- "xapp.additive_unlock_action": "Purchase add-on unlock",
363
- "xapp.checkout_action": "Continue to checkout",
479
+ "xapp.current_access_title": "Current access",
364
480
  "xapp.access_state_label": "Access state",
365
481
  "xapp.access_state_available": "available",
366
- "xapp.subscription_status_label": "Subscription status",
482
+ "xapp.subscription_status_label": "Subscription state",
367
483
  "xapp.subscription_coverage_label": "Coverage",
368
484
  "xapp.subscription_reason_label": "Status reason",
369
485
  "xapp.subscription_overdue_since_label": "Overdue since",
@@ -374,8 +490,22 @@ var MARKETPLACE_CATALOGS = {
374
490
  "xapp.subscription_reason_past_due_after_period_end": "Current period ended without successful renewal",
375
491
  "xapp.subscription_reason_expired_after_boundary": "Expiry boundary reached",
376
492
  "xapp.renews_at_label": "Renews at",
493
+ "xapp.current_period_ends_label": "Current period ends",
494
+ "xapp.cancelled_at_label": "Cancelled at",
377
495
  "xapp.expires_at_label": "Expires at",
378
- "xapp.credits_remaining_label": "Credits remaining",
496
+ "xapp.subscription_refresh_action": "Refresh status",
497
+ "xapp.subscription_refreshing": "Refreshing...",
498
+ "xapp.subscription_refresh_failed": "Unable to refresh subscription state.",
499
+ "xapp.subscription_cancel_action": "Cancel subscription",
500
+ "xapp.subscription_cancelling": "Cancelling...",
501
+ "xapp.subscription_cancel_title": "Cancel subscription?",
502
+ "xapp.subscription_cancel_description": "The subscription will stop renewing. Current access remains available until the current period ends.",
503
+ "xapp.subscription_cancel_failed": "Unable to cancel this subscription.",
504
+ "xapp.lifecycle_preview_at_label": "Preview as of",
505
+ "xapp.lifecycle_preview_hint": "Subscription state is being previewed for the selected time.",
506
+ "xapp.virtual_currency_label": "Currency",
507
+ "xapp.current_balances_label": "Balances now",
508
+ "xapp.credits_remaining_label": "Balance",
379
509
  "xapp.available_label": "Available",
380
510
  "xapp.ready_to_use": "{count} ready to use",
381
511
  "xapp.source_label": "Source",
@@ -517,8 +647,8 @@ var MARKETPLACE_CATALOGS = {
517
647
  "activity.subject_required_desc": "Aceast\u0103 sesiune de host nu este asociat\u0103 cu un utilizator. Cere hostului s\u0103 creeze o sesiune de catalog cu un subjectId.",
518
648
  "activity.showing_requests_for": "Se afi\u0219eaz\u0103 cererile pentru {title}",
519
649
  "activity.showing_requests_for_prefix": "Se afi\u0219eaz\u0103 cererile pentru",
520
- "activity.showing_monetization_for": "Se afi\u0219eaz\u0103 starea XMS pentru {title}",
521
- "activity.showing_monetization_for_prefix": "Se afi\u0219eaz\u0103 starea XMS pentru",
650
+ "activity.showing_monetization_for": "Se afi\u0219eaz\u0103 planurile \u0219i soldurile pentru {title}",
651
+ "activity.showing_monetization_for_prefix": "Se afi\u0219eaz\u0103 planurile \u0219i soldurile pentru",
522
652
  "activity.showing_payments_for": "Se afi\u0219eaz\u0103 activitatea pl\u0103\u021Bilor pentru {title}",
523
653
  "activity.showing_payments_for_prefix": "Se afi\u0219eaz\u0103 activitatea pl\u0103\u021Bilor pentru",
524
654
  "activity.showing_invoices_for": "Se afi\u0219eaz\u0103 facturile pentru {title}",
@@ -534,11 +664,11 @@ var MARKETPLACE_CATALOGS = {
534
664
  "activity.mark_read": "Marcheaz\u0103 ca citit",
535
665
  "activity.unread_count": "{count} notific{suffix} necitit{suffix2}",
536
666
  "activity.loading_requests": "Se \xEEncarc\u0103 cererile...",
537
- "activity.loading_monetization": "Se \xEEncarc\u0103 starea monetiz\u0103rii...",
667
+ "activity.loading_monetization": "Se \xEEncarc\u0103 planurile, soldurile \u0219i activitatea recent\u0103...",
538
668
  "activity.no_requests": "Nu exist\u0103 \xEEnc\u0103 cereri.",
539
- "activity.no_monetization": "Nu exist\u0103 \xEEnc\u0103 aplica\u021Bii cu XMS instalate pentru acest subiect.",
540
- "activity.no_monetization_current": "Nu a fost g\u0103sit\u0103 nicio acoperire curent\u0103 de monetizare pentru acest subiect.",
541
- "activity.no_monetization_history": "Nu a fost g\u0103sit niciun istoric de monetizare pentru acest subiect.",
669
+ "activity.no_monetization": "Nu exist\u0103 \xEEnc\u0103 aplica\u021Bii monetizate instalate pentru acest subiect.",
670
+ "activity.no_monetization_current": "Nu au fost g\u0103site planuri sau solduri curente pentru acest subiect.",
671
+ "activity.no_monetization_history": "Nu a fost g\u0103sit niciun istoric de planuri sau solduri pentru acest subiect.",
542
672
  "activity.loading_payments": "Se \xEEncarc\u0103 pl\u0103\u021Bile...",
543
673
  "activity.no_payments": "Nu a fost g\u0103sit\u0103 activitate de plat\u0103.",
544
674
  "activity.loading_payment_detail": "Se \xEEncarc\u0103 detaliile pl\u0103\u021Bii...",
@@ -553,21 +683,30 @@ var MARKETPLACE_CATALOGS = {
553
683
  "activity.loading_notifications": "Se \xEEncarc\u0103 notific\u0103rile...",
554
684
  "activity.no_notifications": "Nu a fost g\u0103sit\u0103 activitate de notificare.",
555
685
  "activity.loading_notification_detail": "Se \xEEncarc\u0103 detaliile notific\u0103rii...",
556
- "activity.monetization_overview_hint": "Revizuie\u0219te accesul XMS curent, abonamentele \u0219i creditele pentru aplica\u021Biile legate de acest subiect.",
557
- "activity.monetization_overview_hint_with_past": "Revizuie\u0219te accesul XMS curent \u0219i trecut, abonamentele \u0219i creditele pentru aplica\u021Biile acestui subiect.",
558
- "activity.monetization_card_subtitle": "Starea XMS curent\u0103, accesul activ, abonamentele \u0219i creditele pentru aceast\u0103 aplica\u021Bie.",
559
- "activity.monetization_focus_xapp": "Focalizeaz\u0103 aplica\u021Bia",
560
- "activity.monetization_show_past": "Arat\u0103 aplica\u021Biile anterioare",
561
- "activity.monetization_show_current_only": "Arat\u0103 doar aplica\u021Biile curente",
562
- "activity.monetization_open_plans": "Deschide planurile",
563
- "activity.monetization_access_label": "Acces curent",
564
- "activity.monetization_plan_label": "Plan curent",
565
- "activity.monetization_credits_label": "Credite r\u0103mase",
686
+ "activity.monetization_overview_hint": "Revizuie\u0219te planurile, abonamentele \u0219i soldurile curente pentru aplica\u021Biile legate de acest subiect.",
687
+ "activity.monetization_overview_hint_with_past": "Revizuie\u0219te planurile, abonamentele \u0219i soldurile curente \u0219i trecute pentru aplica\u021Biile acestui subiect.",
688
+ "activity.monetization_summary_title": "Planuri \u0219i solduri",
689
+ "activity.monetization_summary_subtitle": "Revizuie\u0219te planurile active, abonamentele \u0219i soldurile \xEEnainte s\u0103 deschizi detaliile aplica\u021Biei sau istoricul.",
690
+ "activity.monetization_summary_apps": "Aplica\u021Bii",
691
+ "activity.monetization_summary_subscriptions": "Abonamente",
692
+ "activity.monetization_summary_balances": "Solduri",
693
+ "activity.monetization_summary_currencies": "Monede nominale",
694
+ "activity.monetization_card_subtitle": "Planurile curente, soldurile \u0219i starea abonamentului pentru aceast\u0103 aplica\u021Bie.",
695
+ "activity.monetization_focus_xapp": "Doar aceast\u0103 aplica\u021Bie",
696
+ "activity.monetization_show_past": "Include aplica\u021Biile anterioare",
697
+ "activity.monetization_show_current_only": "Doar aplica\u021Biile curente",
698
+ "activity.monetization_open_plans": "Vezi planurile",
699
+ "activity.monetization_open_history": "Vezi istoricul",
700
+ "activity.monetization_access_label": "Acces",
701
+ "activity.monetization_plan_label": "Plan",
702
+ "activity.monetization_credits_label": "Sold",
566
703
  "activity.monetization_subscription_label": "Abonament",
567
- "activity.monetization_coverage_label": "Acoperire",
704
+ "activity.monetization_coverage_label": "Stare re\xEEnnoire",
568
705
  "activity.monetization_renews_at": "Se re\xEEnnoie\u0219te la",
569
- "activity.monetization_balance_state": "Stare sold",
570
- "activity.monetization_source_label": "Surs\u0103",
706
+ "activity.monetization_balance_state": "Status sold",
707
+ "activity.monetization_balances_label": "Solduri",
708
+ "activity.monetization_source_label": "Origine",
709
+ "activity.monetization_no_currency": "F\u0103r\u0103 moned\u0103 nominal\u0103",
571
710
  "activity.monetization_unknown": "Necunoscut",
572
711
  "activity.monetization_none": "Niciunul",
573
712
  "activity.monetization_no_source": "F\u0103r\u0103 surs\u0103",
@@ -617,6 +756,7 @@ var MARKETPLACE_CATALOGS = {
617
756
  "activity.guard_action_confirm_action": "Confirm\u0103 ac\u021Biunea",
618
757
  "activity.guard_action_confirm_action_message": "Confirm\u0103 ac\u021Biunea ({message})",
619
758
  "activity.guard_action_custom": "Ac\u021Biune: {kind}",
759
+ ...buildMarketplaceXmsCatalog("ro"),
620
760
  "status.unread": "Necitit",
621
761
  "status.read": "Citit",
622
762
  "common.back": "\xCEnapoi",
@@ -642,7 +782,9 @@ var MARKETPLACE_CATALOGS = {
642
782
  "xapp.update_available": "Actualizare disponibil\u0103",
643
783
  "xapp.about_title": "Despre",
644
784
  "xapp.available_views_title": "Vizualiz\u0103ri disponibile",
785
+ "xapp.open_to_access_views": "Deschide aceast\u0103 aplica\u021Bie pentru a o porni \u0219i instala automat \xEEn spa\u021Biul t\u0103u de lucru.",
645
786
  "xapp.add_to_access_views": "Adaug\u0103 aceast\u0103 aplica\u021Bie \xEEn spa\u021Biul t\u0103u de lucru pentru a-i accesa vizualiz\u0103rile disponibile.",
787
+ "xapp.update_to_access_views_auto": "Deschide o vizualizare pentru a actualiza automat aplica\u021Bia \xEEn spa\u021Biul t\u0103u de lucru.",
646
788
  "xapp.update_to_access_views": "Este disponibil\u0103 o actualizare. Actualizeaz\u0103 aplica\u021Bia pentru a-i accesa vizualiz\u0103rile disponibile.",
647
789
  "xapp.load_as_user_to_access": "\xCEncarc\u0103 catalogul ca utilizator pentru a accesa aceast\u0103 aplica\u021Bie.",
648
790
  "xapp.no_views_available": "Nu exist\u0103 \xEEn prezent vizualiz\u0103ri disponibile pentru aplica\u021Bie.",
@@ -667,16 +809,6 @@ var MARKETPLACE_CATALOGS = {
667
809
  "xapp.screenshot_alt": "Captur\u0103 de ecran {index}",
668
810
  "xapp.usage_credits_title": "Credite de utilizare",
669
811
  "xapp.current_access_title": "Acces curent",
670
- "xapp.current_plan_label": "Plan curent",
671
- "xapp.selected_label": "Selectat",
672
- "xapp.default_label": "Implicit",
673
- "xapp.owned_unlock_label": "Unlock de\u021Binut",
674
- "xapp.additive_unlock_label": "Supliment cu abonament",
675
- "xapp.owned_unlock_active": "Unlock deja activ",
676
- "xapp.current_plan_active": "Plan activ",
677
- "xapp.checkout_starting": "Se porne\u0219te checkout-ul...",
678
- "xapp.additive_unlock_action": "Cump\u0103r\u0103 suplimentul",
679
- "xapp.checkout_action": "Continu\u0103 spre checkout",
680
812
  "xapp.access_state_label": "Stare acces",
681
813
  "xapp.access_state_available": "disponibil",
682
814
  "xapp.subscription_status_label": "Stare abonament",
@@ -690,8 +822,22 @@ var MARKETPLACE_CATALOGS = {
690
822
  "xapp.subscription_reason_past_due_after_period_end": "Perioada curent\u0103 s-a \xEEncheiat f\u0103r\u0103 re\xEEnnoire reu\u0219it\u0103",
691
823
  "xapp.subscription_reason_expired_after_boundary": "A fost atins\u0103 limita de expirare",
692
824
  "xapp.renews_at_label": "Se re\xEEnnoie\u0219te la",
825
+ "xapp.current_period_ends_label": "Perioada curent\u0103 se \xEEncheie la",
826
+ "xapp.cancelled_at_label": "Anulat la",
693
827
  "xapp.expires_at_label": "Expir\u0103 la",
694
- "xapp.credits_remaining_label": "Credite r\u0103mase",
828
+ "xapp.subscription_refresh_action": "Actualizeaz\u0103 starea",
829
+ "xapp.subscription_refreshing": "Se actualizeaz\u0103...",
830
+ "xapp.subscription_refresh_failed": "Starea abonamentului nu a putut fi actualizat\u0103.",
831
+ "xapp.subscription_cancel_action": "Anuleaz\u0103 abonamentul",
832
+ "xapp.subscription_cancelling": "Se anuleaz\u0103...",
833
+ "xapp.subscription_cancel_title": "Anulezi abonamentul?",
834
+ "xapp.subscription_cancel_description": "Abonamentul nu se va mai re\xEEnnoi. Accesul curent r\u0103m\xE2ne disponibil p\xE2n\u0103 la sf\xE2r\u0219itul perioadei curente.",
835
+ "xapp.subscription_cancel_failed": "Abonamentul nu a putut fi anulat.",
836
+ "xapp.lifecycle_preview_at_label": "Previzualizare la",
837
+ "xapp.lifecycle_preview_hint": "Ciclul de via\u021B\u0103 al abonamentului este previzualizat pentru momentul selectat.",
838
+ "xapp.virtual_currency_label": "Moned\u0103 virtual\u0103",
839
+ "xapp.current_balances_label": "Solduri curente",
840
+ "xapp.credits_remaining_label": "Sold",
695
841
  "xapp.available_label": "Disponibile",
696
842
  "xapp.ready_to_use": "{count} gata de utilizare",
697
843
  "xapp.source_label": "Surs\u0103",
@@ -2012,20 +2158,13 @@ function InvoicesPage() {
2012
2158
  ] });
2013
2159
  }
2014
2160
 
2015
- // ../browser-host/src/xms.ts
2161
+ // ../browser-host/src/xmsCopy.ts
2016
2162
  function readString3(value) {
2017
2163
  return String(value ?? "").trim();
2018
2164
  }
2019
- function readNumber(value, fallback = 0) {
2020
- const parsed = Number(value);
2021
- return Number.isFinite(parsed) ? parsed : fallback;
2022
- }
2023
2165
  function readLower(value) {
2024
2166
  return readString3(value).toLowerCase();
2025
2167
  }
2026
- function readBoolean(value, fallback = false) {
2027
- return typeof value === "boolean" ? value : fallback;
2028
- }
2029
2168
  function isRomanianLocale(value) {
2030
2169
  const locale = readLower(value);
2031
2170
  return locale === "ro" || locale.startsWith("ro-");
@@ -2043,23 +2182,68 @@ var XMS_COPY_CATALOG = {
2043
2182
  currentPlanActiveLabel: "Current plan active",
2044
2183
  startingCheckoutLabel: "Starting checkout...",
2045
2184
  purchaseAddOnUnlockLabel: "Purchase add-on unlock",
2046
- continueToCheckoutLabel: "Continue to checkout"
2185
+ continueToCheckoutLabel: "Continue to checkout",
2186
+ generalUpgradeFitLabel: "Flexible option",
2187
+ generalUpgradeSummary: "A general plan option for this app.",
2188
+ durableUnlockFitLabel: "One-time unlock",
2189
+ durableUnlockSummary: "Best when you want access without an ongoing subscription.",
2190
+ recurringMembershipFitLabel: "Subscription",
2191
+ recurringMembershipSummary: "Best when this app is meant to stay active through recurring coverage.",
2192
+ creditTopUpFitLabel: "Balance top-up",
2193
+ hybridUpgradeFitLabel: "Access + balance",
2194
+ creditPackFitSummary: (unitLabel) => `Best when the feature spends ${unitLabel} for each advanced action.`,
2195
+ hybridPackFitSummary: (unitLabel) => `Blends access coverage with bundled ${unitLabel} for mixed workflows.`,
2196
+ packageCurrencySignalLabel: (unitLabel) => `currency ${unitLabel}`,
2197
+ billedSignalLabel: (periodLabel) => `billed ${periodLabel}`,
2198
+ generalOfferingSummary: "Available plans for this app.",
2199
+ featurePaywallOfferingSummary: "Shown when this app needs extra access or balance.",
2200
+ defaultPaywallOfferingSummary: "Main plan selection for this app.",
2201
+ checkoutOfferingSummary: "Direct purchase flow for this app.",
2202
+ upgradeOfferingSummary: "Best for switching or upgrading your current plan.",
2203
+ featureDurableUnlockReason: "Aligned with one-time unlock access.",
2204
+ featureRecurringAccessReason: "Recurring membership also grants current access.",
2205
+ featureHybridAccessReason: "Hybrid package contributes to current access coverage.",
2206
+ featureSubscriptionDirectReason: "Matches the subscription requirement directly.",
2207
+ featureHybridSubscriptionReason: "Hybrid package can also cover part of the subscription shape.",
2208
+ creditRequirementCoveredLabel: (amountLabel) => `Covers the ${amountLabel} requirement.`,
2209
+ creditRequirementAddedLabel: (amountLabel) => `Adds ${amountLabel} toward the requirement.`,
2210
+ hybridCreditsSupportLabel: (unitLabel) => `Hybrid package can add bundled ${unitLabel} for this flow.`
2047
2211
  },
2048
2212
  surface: {
2049
2213
  plansTitle: "Plans",
2050
2214
  historyTitle: "History",
2051
- plansSubtitle: "Current access and published plans for this app",
2215
+ plansSubtitle: "Access, plans, and balances for this app",
2052
2216
  historySubtitle: "Recent monetization events, invoices, subscriptions, and wallet activity",
2217
+ offeringFallbackLabel: "Offering",
2218
+ packageFallbackLabel: "Package",
2219
+ paywallFallbackLabel: "Plans",
2220
+ availableLabel: "Available",
2221
+ unavailableLabel: "Unavailable",
2222
+ unknownLabel: "Unknown",
2223
+ yesLabel: "Yes",
2224
+ noLabel: "No",
2225
+ defaultBadgeLabel: "default",
2226
+ choosePackageActionLabel: "Choose package",
2227
+ noPaywallPackagesLabel: "No plans are currently available.",
2228
+ priceUnavailableLabel: "Price unavailable",
2053
2229
  plansLabel: "Plans",
2054
2230
  historyLabel: "History",
2055
2231
  closeLabel: "Close",
2056
- tabsAriaLabel: "XMS view",
2232
+ tabsAriaLabel: "Plans and history view",
2057
2233
  loadingLabel: "Loading plans...",
2058
2234
  subjectRequiredNotice: "Checkout requires a subject-bound catalog session. Start from a signed host session to purchase plans.",
2059
2235
  paymentCompletedNotice: "Payment completed and access was refreshed.",
2060
2236
  checkoutCancelledNotice: "Checkout was cancelled before completion.",
2061
2237
  paymentFailedNotice: "Payment failed before access could be issued.",
2062
- missingPackageMetadataMessage: "This package is missing purchase metadata in the published paywall.",
2238
+ subscriptionRefreshCompletedNotice: "Subscription status was refreshed.",
2239
+ subscriptionRefreshFailedNotice: "Subscription status could not be refreshed.",
2240
+ subscriptionCancelCompletedNotice: "Subscription renewal was cancelled.",
2241
+ subscriptionCancelFailedNotice: "Subscription could not be cancelled.",
2242
+ subscriptionCancelConfirmTitle: "Cancel subscription",
2243
+ subscriptionCancelConfirmMessage: "Cancel renewal for this subscription?",
2244
+ subscriptionCancelConfirmLabel: "Cancel subscription",
2245
+ subscriptionCancelDismissLabel: "Keep subscription",
2246
+ missingPackageMetadataMessage: "This package is missing purchase metadata in the published plans configuration.",
2063
2247
  missingIntentMessage: "Purchase intent was created without an identifier.",
2064
2248
  missingPaymentPageMessage: "Payment page is not available for this package.",
2065
2249
  startCheckoutFailedMessage: "Unable to start checkout for this package.",
@@ -2067,22 +2251,63 @@ var XMS_COPY_CATALOG = {
2067
2251
  currentCoverageTitle: "Current coverage",
2068
2252
  currentPlanLabel: "Current plan",
2069
2253
  membershipAccessLabel: "Membership access",
2070
- subscriptionStatusLabel: "Subscription status",
2254
+ subscriptionStatusLabel: "Subscription state",
2255
+ subscriptionCoverageLabel: "Coverage",
2256
+ subscriptionReasonLabel: "Status reason",
2257
+ currentPeriodEndsLabel: "Current period ends",
2071
2258
  renewsAtLabel: "Renews at",
2072
2259
  expiresAtLabel: "Expires at",
2073
- creditsRemainingLabel: "Credits remaining",
2260
+ overdueSinceLabel: "Overdue since",
2261
+ expiryBoundaryLabel: "Expiry boundary",
2262
+ cancelledAtLabel: "Cancelled at",
2263
+ operatorAuthorityLabel: "Operator authority",
2264
+ managementDestinationLabel: "Manage in",
2265
+ operatorAuthorityGatewayLabel: "Gateway",
2266
+ operatorAuthorityTenantLabel: "Tenant",
2267
+ operatorAuthorityPublisherLabel: "Publisher",
2268
+ operatorAuthorityOwnerLabel: "App owner",
2269
+ managementDestinationGatewayLabel: "Gateway admin",
2270
+ managementDestinationTenantLabel: "Tenant app",
2271
+ managementDestinationPublisherLabel: "Publisher app",
2272
+ managementDestinationOwnerLabel: "App owner",
2273
+ managementDestinationHintGatewayLabel: "Advanced subscription management is handled in Gateway admin.",
2274
+ managementDestinationHintTenantLabel: "Advanced subscription management is handled in the tenant app.",
2275
+ managementDestinationHintPublisherLabel: "Advanced subscription management is handled in the publisher app.",
2276
+ managementDestinationHintOwnerLabel: "Advanced subscription management is handled by the app owner.",
2277
+ openManagementDestinationActionLabel: "Open management",
2278
+ virtualCurrencyLabel: "Currency",
2279
+ creditsRemainingLabel: "Balance",
2074
2280
  addOnUnlocksLabel: "Add-on unlocks",
2075
- noPublishedPlansLabel: "No published plans are currently available.",
2076
- recentTimelineTitle: "Recent timeline",
2077
- recentTimelineSubtitle: "Latest monetization events correlated for this subject and app.",
2078
- historyAuditTitle: "History and audit",
2079
- historyAuditSubtitle: "Recent monetization records for this subject and app.",
2281
+ coverageActiveLabel: "Still covered",
2282
+ coverageInactiveLabel: "Not covered",
2283
+ noOverdueRestrictionLabel: "No active overdue restriction.",
2284
+ reasonGraceCoveredPastDueLabel: "Coverage remains during grace period",
2285
+ reasonPastDueAfterPeriodEndLabel: "Current period ended without successful renewal",
2286
+ reasonExpiredAfterBoundaryLabel: "Expiry boundary reached",
2287
+ refreshStatusActionLabel: "Refresh status",
2288
+ refreshingStatusActionLabel: "Refreshing...",
2289
+ cancelSubscriptionActionLabel: "Cancel subscription",
2290
+ cancellingSubscriptionActionLabel: "Cancelling...",
2291
+ noPublishedPlansLabel: "No plans are currently available.",
2292
+ recentTimelineTitle: "Recent activity",
2293
+ recentTimelineSubtitle: "Latest subscription, balance, purchase, and invoice activity for this app.",
2294
+ historyAuditTitle: "Detailed history",
2295
+ historyAuditSubtitle: "Recent records grouped by subscriptions, balances, purchases, and invoices.",
2296
+ historyBalanceSummaryTitle: "Balances now",
2297
+ historyBalanceSummarySubtitle: "Latest visible wallet balances grouped by virtual currency for this app.",
2080
2298
  noHistoryAvailableLabel: "No monetization history is available for this app yet.",
2081
2299
  historyGenericLabel: "History",
2082
2300
  historyPurchaseIntentsTitle: "Purchase intents",
2083
2301
  historyPurchaseIntentLabel: "Purchase intent",
2084
2302
  historyTransactionsTitle: "Transactions",
2085
2303
  historyTransactionLabel: "Transaction",
2304
+ historySettlementDetailDisputeWarningNeedsResponse: "Dispute warning: response needed",
2305
+ historySettlementDetailDisputeWarningUnderReview: "Dispute warning under review",
2306
+ historySettlementDetailDisputeWarningClosed: "Dispute warning closed",
2307
+ historySettlementDetailDisputeNeedsResponse: "Dispute needs response",
2308
+ historySettlementDetailDisputeUnderReview: "Dispute under review",
2309
+ historySettlementDetailDisputeWon: "Dispute won",
2310
+ historySettlementDetailDisputeLost: "Dispute lost",
2086
2311
  historySubscriptionsTitle: "Subscriptions",
2087
2312
  historySubscriptionContractLabel: "Subscription contract",
2088
2313
  historyEntitlementsTitle: "Entitlements",
@@ -2094,7 +2319,33 @@ var XMS_COPY_CATALOG = {
2094
2319
  historyAccessSnapshotsTitle: "Access snapshots",
2095
2320
  historyAccessSnapshotLabel: "Access snapshot",
2096
2321
  historyInvoicesTitle: "Invoices",
2097
- historyInvoiceLabel: "Invoice"
2322
+ historyInvoiceLabel: "Invoice",
2323
+ featureCurrentAccessMissingLabel: "Current access coverage is not active on this scope.",
2324
+ featureSubscriptionMissingLabel: "No active subscription is visible for this scope.",
2325
+ featureCreditsMissingLabel: (requiredLabel, availableLabel) => `This action needs ${requiredLabel}, but only ${availableLabel} are visible right now.`,
2326
+ featureBlockedSummary: (title) => `${title || "Feature"} is blocked on the current scope.`,
2327
+ featureReadySummary: (title) => `${title || "Feature"} can be unlocked from the current plan options.`,
2328
+ featureNeedMixedAccessLabel: "needs mixed access",
2329
+ featureNeedMembershipAndCreditsLabel: (unitLabel) => `needs membership + ${unitLabel}`,
2330
+ featureNeedMembershipLabel: "needs membership",
2331
+ featureNeedCreditsLabel: (unitLabel) => `needs ${unitLabel}`,
2332
+ featureNeedAccessLabel: "needs access",
2333
+ featureLockedLabel: "locked",
2334
+ featureGapShortLabel: (amountLabel) => `${amountLabel} short`,
2335
+ featureCurrentAccessMissingBadge: "current access missing",
2336
+ featureMembershipNotActiveBadge: "membership not active",
2337
+ featureCandidateLead: (selectedPackageTitle) => `${selectedPackageTitle || "Selected package"} is one package candidate for this access gap.`,
2338
+ featureCandidateFallbackLead: "Choose a plan option that covers the current access gap.",
2339
+ featureViewHybridOptionsLabel: "View hybrid options",
2340
+ featureViewMembershipOptionsLabel: "View membership options",
2341
+ featureViewCreditOptionsLabel: (unitLabel) => `View ${unitLabel} options`,
2342
+ featureViewUnlockOptionsLabel: "View unlock options",
2343
+ featureOpenPaywallLabel: "Open plans",
2344
+ featureUnlockCheckoutLabel: "Unlock with hosted checkout",
2345
+ featureStartMembershipCheckoutLabel: "Start membership checkout",
2346
+ featureBuyCreditsCheckoutLabel: (unitLabel) => `Buy ${unitLabel} with hosted checkout`,
2347
+ featureStartHybridCheckoutLabel: "Start hybrid checkout",
2348
+ featureCreatePaymentSessionLabel: "Create payment session"
2098
2349
  }
2099
2350
  },
2100
2351
  ro: {
@@ -2109,23 +2360,68 @@ var XMS_COPY_CATALOG = {
2109
2360
  currentPlanActiveLabel: "Plan activ",
2110
2361
  startingCheckoutLabel: "Se porne\u0219te checkout-ul...",
2111
2362
  purchaseAddOnUnlockLabel: "Cump\u0103r\u0103 suplimentul",
2112
- continueToCheckoutLabel: "Continu\u0103 spre checkout"
2363
+ continueToCheckoutLabel: "Continu\u0103 spre checkout",
2364
+ generalUpgradeFitLabel: "Op\u021Biune flexibil\u0103",
2365
+ generalUpgradeSummary: "O op\u021Biune general\u0103 de plan pentru aceast\u0103 aplica\u021Bie.",
2366
+ durableUnlockFitLabel: "Unlock unic",
2367
+ durableUnlockSummary: "Potrivit c\xE2nd vrei acces f\u0103r\u0103 un abonament recurent.",
2368
+ recurringMembershipFitLabel: "Abonament",
2369
+ recurringMembershipSummary: "Potrivit c\xE2nd aceast\u0103 aplica\u021Bie trebuie s\u0103 r\u0103m\xE2n\u0103 activ\u0103 prin acoperire recurent\u0103.",
2370
+ creditTopUpFitLabel: "Top-up sold",
2371
+ hybridUpgradeFitLabel: "Acces + sold",
2372
+ creditPackFitSummary: (unitLabel) => `Potrivit c\xE2nd func\u021Bia consum\u0103 ${unitLabel} pentru fiecare ac\u021Biune avansat\u0103.`,
2373
+ hybridPackFitSummary: (unitLabel) => `Combin\u0103 acoperirea accesului cu ${unitLabel} incluse pentru fluxuri mixte.`,
2374
+ packageCurrencySignalLabel: (unitLabel) => `moned\u0103 ${unitLabel}`,
2375
+ billedSignalLabel: (periodLabel) => `facturat ${periodLabel}`,
2376
+ generalOfferingSummary: "Planuri disponibile pentru aceast\u0103 aplica\u021Bie.",
2377
+ featurePaywallOfferingSummary: "Afi\u0219at c\xE2nd aceast\u0103 aplica\u021Bie are nevoie de acces sau sold suplimentar.",
2378
+ defaultPaywallOfferingSummary: "Selec\u021Bia principal\u0103 de planuri pentru aceast\u0103 aplica\u021Bie.",
2379
+ checkoutOfferingSummary: "Flux de cump\u0103rare direct pentru aceast\u0103 aplica\u021Bie.",
2380
+ upgradeOfferingSummary: "Potrivit pentru schimbarea sau \xEEmbun\u0103t\u0103\u021Birea planului curent.",
2381
+ featureDurableUnlockReason: "Se potrive\u0219te cu accesul de tip unlock unic.",
2382
+ featureRecurringAccessReason: "Abonamentul recurent ofer\u0103 \u0219i acces curent pentru acest flux.",
2383
+ featureHybridAccessReason: "Pachetul hibrid contribuie la acoperirea accesului curent.",
2384
+ featureSubscriptionDirectReason: "Se potrive\u0219te direct cu cerin\u021Ba de abonament.",
2385
+ featureHybridSubscriptionReason: "Pachetul hibrid poate acoperi \u0219i o parte din forma de abonament.",
2386
+ creditRequirementCoveredLabel: (amountLabel) => `Acoper\u0103 cerin\u021Ba de ${amountLabel}.`,
2387
+ creditRequirementAddedLabel: (amountLabel) => `Adaug\u0103 ${amountLabel} c\u0103tre cerin\u021B\u0103.`,
2388
+ hybridCreditsSupportLabel: (unitLabel) => `Pachetul hibrid poate ad\u0103uga ${unitLabel} incluse pentru acest flux.`
2113
2389
  },
2114
2390
  surface: {
2115
2391
  plansTitle: "Planuri",
2116
2392
  historyTitle: "Istoric",
2117
- plansSubtitle: "Accesul curent \u0219i planurile publicate pentru aceast\u0103 aplica\u021Bie",
2393
+ plansSubtitle: "Acces, planuri \u0219i solduri pentru aceast\u0103 aplica\u021Bie",
2118
2394
  historySubtitle: "Evenimente recente de monetizare, facturi, abonamente \u0219i activitate din portofel",
2395
+ offeringFallbackLabel: "Ofert\u0103",
2396
+ packageFallbackLabel: "Pachet",
2397
+ paywallFallbackLabel: "Planuri",
2398
+ availableLabel: "Disponibil",
2399
+ unavailableLabel: "Indisponibil",
2400
+ unknownLabel: "Necunoscut",
2401
+ yesLabel: "Da",
2402
+ noLabel: "Nu",
2403
+ defaultBadgeLabel: "implicit",
2404
+ choosePackageActionLabel: "Alege pachetul",
2405
+ noPaywallPackagesLabel: "Nu exist\u0103 momentan planuri disponibile.",
2406
+ priceUnavailableLabel: "Pre\u021B indisponibil",
2119
2407
  plansLabel: "Planuri",
2120
2408
  historyLabel: "Istoric",
2121
2409
  closeLabel: "\xCEnchide",
2122
- tabsAriaLabel: "Vizualizare XMS",
2410
+ tabsAriaLabel: "Vizualizare planuri \u0219i istoric",
2123
2411
  loadingLabel: "Se \xEEncarc\u0103 planurile...",
2124
2412
  subjectRequiredNotice: "Checkout-ul necesit\u0103 o sesiune de catalog asociat\u0103 unui subiect. Porne\u0219te dintr-o sesiune gazd\u0103 autentificat\u0103 pentru a cump\u0103ra planuri.",
2125
2413
  paymentCompletedNotice: "Plata a fost finalizat\u0103 \u0219i accesul a fost actualizat.",
2126
2414
  checkoutCancelledNotice: "Checkout-ul a fost anulat \xEEnainte de finalizare.",
2127
2415
  paymentFailedNotice: "Plata a e\u0219uat \xEEnainte ca accesul s\u0103 poat\u0103 fi acordat.",
2128
- missingPackageMetadataMessage: "Acest pachet nu are metadatele de cump\u0103rare necesare \xEEn paywall-ul publicat.",
2416
+ subscriptionRefreshCompletedNotice: "Starea abonamentului a fost actualizat\u0103.",
2417
+ subscriptionRefreshFailedNotice: "Starea abonamentului nu a putut fi actualizat\u0103.",
2418
+ subscriptionCancelCompletedNotice: "Re\xEEnnoirea abonamentului a fost anulat\u0103.",
2419
+ subscriptionCancelFailedNotice: "Abonamentul nu a putut fi anulat.",
2420
+ subscriptionCancelConfirmTitle: "Anuleaz\u0103 abonamentul",
2421
+ subscriptionCancelConfirmMessage: "Anulezi re\xEEnnoirea acestui abonament?",
2422
+ subscriptionCancelConfirmLabel: "Anuleaz\u0103 abonamentul",
2423
+ subscriptionCancelDismissLabel: "P\u0103streaz\u0103 abonamentul",
2424
+ missingPackageMetadataMessage: "Acest pachet nu are metadatele de cump\u0103rare necesare \xEEn configura\u021Bia publicat\u0103 a planurilor.",
2129
2425
  missingIntentMessage: "Intentul de cump\u0103rare a fost creat f\u0103r\u0103 identificator.",
2130
2426
  missingPaymentPageMessage: "Pagina de plat\u0103 nu este disponibil\u0103 pentru acest pachet.",
2131
2427
  startCheckoutFailedMessage: "Nu s-a putut porni checkout-ul pentru acest pachet.",
@@ -2134,21 +2430,62 @@ var XMS_COPY_CATALOG = {
2134
2430
  currentPlanLabel: "Plan curent",
2135
2431
  membershipAccessLabel: "Acces de membru",
2136
2432
  subscriptionStatusLabel: "Stare abonament",
2433
+ subscriptionCoverageLabel: "Acoperire",
2434
+ subscriptionReasonLabel: "Motiv stare",
2435
+ currentPeriodEndsLabel: "Perioada curent\u0103 se \xEEncheie la",
2137
2436
  renewsAtLabel: "Se re\xEEnnoie\u0219te la",
2138
2437
  expiresAtLabel: "Expir\u0103 la",
2139
- creditsRemainingLabel: "Credite r\u0103mase",
2438
+ overdueSinceLabel: "Restant din",
2439
+ expiryBoundaryLabel: "Limit\u0103 expirare",
2440
+ cancelledAtLabel: "Anulat la",
2441
+ operatorAuthorityLabel: "Autoritate operator",
2442
+ managementDestinationLabel: "Administreaz\u0103 \xEEn",
2443
+ operatorAuthorityGatewayLabel: "Gateway",
2444
+ operatorAuthorityTenantLabel: "Tenant",
2445
+ operatorAuthorityPublisherLabel: "Publisher",
2446
+ operatorAuthorityOwnerLabel: "Proprietar aplica\u021Bie",
2447
+ managementDestinationGatewayLabel: "Administrare gateway",
2448
+ managementDestinationTenantLabel: "Aplica\u021Bia tenantului",
2449
+ managementDestinationPublisherLabel: "Aplica\u021Bia publisherului",
2450
+ managementDestinationOwnerLabel: "Proprietarul aplica\u021Biei",
2451
+ managementDestinationHintGatewayLabel: "Administrarea avansat\u0103 a abonamentului se face \xEEn administrarea gateway-ului.",
2452
+ managementDestinationHintTenantLabel: "Administrarea avansat\u0103 a abonamentului se face \xEEn aplica\u021Bia tenantului.",
2453
+ managementDestinationHintPublisherLabel: "Administrarea avansat\u0103 a abonamentului se face \xEEn aplica\u021Bia publisherului.",
2454
+ managementDestinationHintOwnerLabel: "Administrarea avansat\u0103 a abonamentului este gestionat\u0103 de proprietarul aplica\u021Biei.",
2455
+ openManagementDestinationActionLabel: "Deschide administrarea",
2456
+ virtualCurrencyLabel: "Moned\u0103 virtual\u0103",
2457
+ creditsRemainingLabel: "Sold",
2140
2458
  addOnUnlocksLabel: "Unlock-uri suplimentare",
2141
- noPublishedPlansLabel: "Nu exist\u0103 planuri publicate disponibile \xEEn acest moment.",
2142
- recentTimelineTitle: "Cronologie recent\u0103",
2143
- recentTimelineSubtitle: "Cele mai recente evenimente de monetizare corelate pentru acest subiect \u0219i aceast\u0103 aplica\u021Bie.",
2144
- historyAuditTitle: "Istoric \u0219i audit",
2145
- historyAuditSubtitle: "\xCEnregistr\u0103ri recente de monetizare pentru acest subiect \u0219i aceast\u0103 aplica\u021Bie.",
2459
+ coverageActiveLabel: "\xCEnc\u0103 activ",
2460
+ coverageInactiveLabel: "Neacoperit",
2461
+ noOverdueRestrictionLabel: "Nu exist\u0103 restric\u021Bii active de \xEEnt\xE2rziere.",
2462
+ reasonGraceCoveredPastDueLabel: "Accesul r\u0103m\xE2ne activ \xEEn perioada de gra\u021Bie",
2463
+ reasonPastDueAfterPeriodEndLabel: "Perioada curent\u0103 s-a \xEEncheiat f\u0103r\u0103 o re\xEEnnoire reu\u0219it\u0103",
2464
+ reasonExpiredAfterBoundaryLabel: "A fost atins\u0103 limita de expirare",
2465
+ refreshStatusActionLabel: "Actualizeaz\u0103 starea",
2466
+ refreshingStatusActionLabel: "Se actualizeaz\u0103...",
2467
+ cancelSubscriptionActionLabel: "Anuleaz\u0103 abonamentul",
2468
+ cancellingSubscriptionActionLabel: "Se anuleaz\u0103...",
2469
+ noPublishedPlansLabel: "Nu exist\u0103 planuri disponibile \xEEn acest moment.",
2470
+ recentTimelineTitle: "Activitate recent\u0103",
2471
+ recentTimelineSubtitle: "Cele mai recente actualiz\u0103ri pentru abonamente, solduri, cump\u0103r\u0103ri \u0219i facturi pentru aceast\u0103 aplica\u021Bie.",
2472
+ historyAuditTitle: "Istoric detaliat",
2473
+ historyAuditSubtitle: "\xCEnregistr\u0103ri recente grupate dup\u0103 abonamente, solduri, cump\u0103r\u0103ri \u0219i facturi.",
2474
+ historyBalanceSummaryTitle: "Solduri acum",
2475
+ historyBalanceSummarySubtitle: "Cele mai recente solduri vizibile din portofel, grupate dup\u0103 moneda virtual\u0103 pentru aceast\u0103 aplica\u021Bie.",
2146
2476
  noHistoryAvailableLabel: "Nu exist\u0103 \xEEnc\u0103 istoric de monetizare disponibil pentru aceast\u0103 aplica\u021Bie.",
2147
2477
  historyGenericLabel: "Istoric",
2148
2478
  historyPurchaseIntentsTitle: "Inten\u021Bii de cump\u0103rare",
2149
2479
  historyPurchaseIntentLabel: "Inten\u021Bie de cump\u0103rare",
2150
2480
  historyTransactionsTitle: "Tranzac\u021Bii",
2151
2481
  historyTransactionLabel: "Tranzac\u021Bie",
2482
+ historySettlementDetailDisputeWarningNeedsResponse: "Avertisment disput\u0103: este necesar un r\u0103spuns",
2483
+ historySettlementDetailDisputeWarningUnderReview: "Avertisment disput\u0103 \xEEn analiz\u0103",
2484
+ historySettlementDetailDisputeWarningClosed: "Avertisment disput\u0103 \xEEnchis",
2485
+ historySettlementDetailDisputeNeedsResponse: "Disput\u0103 ce necesit\u0103 r\u0103spuns",
2486
+ historySettlementDetailDisputeUnderReview: "Disput\u0103 \xEEn analiz\u0103",
2487
+ historySettlementDetailDisputeWon: "Disput\u0103 c\xE2\u0219tigat\u0103",
2488
+ historySettlementDetailDisputeLost: "Disput\u0103 pierdut\u0103",
2152
2489
  historySubscriptionsTitle: "Abonamente",
2153
2490
  historySubscriptionContractLabel: "Contract de abonament",
2154
2491
  historyEntitlementsTitle: "Drepturi de acces",
@@ -2160,7 +2497,33 @@ var XMS_COPY_CATALOG = {
2160
2497
  historyAccessSnapshotsTitle: "Instantanee acces",
2161
2498
  historyAccessSnapshotLabel: "Instantaneu acces",
2162
2499
  historyInvoicesTitle: "Facturi",
2163
- historyInvoiceLabel: "Factur\u0103"
2500
+ historyInvoiceLabel: "Factur\u0103",
2501
+ featureCurrentAccessMissingLabel: "Acoperirea de acces curent nu este activ\u0103 pe acest scope.",
2502
+ featureSubscriptionMissingLabel: "Nu este vizibil niciun abonament activ pentru acest scope.",
2503
+ featureCreditsMissingLabel: (requiredLabel, availableLabel) => `Aceast\u0103 ac\u021Biune are nevoie de ${requiredLabel}, dar acum sunt vizibile doar ${availableLabel}.`,
2504
+ featureBlockedSummary: (title) => `${title || "Func\u021Bia"} este blocat\u0103 pe scope-ul curent.`,
2505
+ featureReadySummary: (title) => `${title || "Func\u021Bia"} poate fi deblocat\u0103 din op\u021Biunile curente de plan.`,
2506
+ featureNeedMixedAccessLabel: "necesit\u0103 acces mixt",
2507
+ featureNeedMembershipAndCreditsLabel: (unitLabel) => `necesit\u0103 abonament + ${unitLabel}`,
2508
+ featureNeedMembershipLabel: "necesit\u0103 abonament",
2509
+ featureNeedCreditsLabel: (unitLabel) => `necesit\u0103 ${unitLabel}`,
2510
+ featureNeedAccessLabel: "necesit\u0103 acces",
2511
+ featureLockedLabel: "blocat",
2512
+ featureGapShortLabel: (amountLabel) => `lipse\u0219te ${amountLabel}`,
2513
+ featureCurrentAccessMissingBadge: "lipse\u0219te accesul curent",
2514
+ featureMembershipNotActiveBadge: "abonamentul nu este activ",
2515
+ featureCandidateLead: (selectedPackageTitle) => `${selectedPackageTitle || "Pachetul selectat"} este un pachet candidat pentru acest gol de acces.`,
2516
+ featureCandidateFallbackLead: "Alege o op\u021Biune de plan care acoper\u0103 golul curent de acces.",
2517
+ featureViewHybridOptionsLabel: "Vezi op\u021Biunile hibride",
2518
+ featureViewMembershipOptionsLabel: "Vezi op\u021Biunile de abonament",
2519
+ featureViewCreditOptionsLabel: (unitLabel) => `Vezi op\u021Biunile ${unitLabel}`,
2520
+ featureViewUnlockOptionsLabel: "Vezi op\u021Biunile de unlock",
2521
+ featureOpenPaywallLabel: "Deschide planurile",
2522
+ featureUnlockCheckoutLabel: "Deblocheaz\u0103 prin checkout g\u0103zduit",
2523
+ featureStartMembershipCheckoutLabel: "Porne\u0219te checkout-ul de abonament",
2524
+ featureBuyCreditsCheckoutLabel: (unitLabel) => `Cump\u0103r\u0103 ${unitLabel} prin checkout g\u0103zduit`,
2525
+ featureStartHybridCheckoutLabel: "Porne\u0219te checkout-ul hibrid",
2526
+ featureCreatePaymentSessionLabel: "Creeaz\u0103 sesiunea de plat\u0103"
2164
2527
  }
2165
2528
  }
2166
2529
  };
@@ -2170,15 +2533,65 @@ function resolveXmsCopyLocale(locale) {
2170
2533
  function buildXmsPackageCopy(locale) {
2171
2534
  return XMS_COPY_CATALOG[resolveXmsCopyLocale(locale)].package;
2172
2535
  }
2536
+ function buildXmsSurfaceCopy(input) {
2537
+ return XMS_COPY_CATALOG[resolveXmsCopyLocale(input?.locale)].surface;
2538
+ }
2539
+
2540
+ // ../browser-host/src/xms.ts
2541
+ function readString4(value) {
2542
+ return String(value ?? "").trim();
2543
+ }
2544
+ function readNumber(value, fallback = 0) {
2545
+ const parsed = Number(value);
2546
+ return Number.isFinite(parsed) ? parsed : fallback;
2547
+ }
2548
+ function readLower2(value) {
2549
+ return readString4(value).toLowerCase();
2550
+ }
2551
+ function readBoolean(value, fallback = false) {
2552
+ return typeof value === "boolean" ? value : fallback;
2553
+ }
2173
2554
  function readLocalizedText(value, fallback = "") {
2174
2555
  if (typeof value === "string") {
2175
- return readString3(value) || fallback;
2556
+ return readString4(value) || fallback;
2176
2557
  }
2177
2558
  if (!value || typeof value !== "object" || Array.isArray(value)) {
2178
2559
  return fallback;
2179
2560
  }
2180
2561
  const record = value;
2181
- return readString3(record.en) || readString3(record.ro) || Object.values(record).map((item) => readString3(item)).find(Boolean) || fallback;
2562
+ return readString4(record.en) || readString4(record.ro) || Object.values(record).map((item) => readString4(item)).find(Boolean) || fallback;
2563
+ }
2564
+ function readVirtualCurrencyDefinition(value) {
2565
+ const record = readRecord(value);
2566
+ if (!record) return null;
2567
+ const code = readString4(record.code);
2568
+ const name = readString4(record.name);
2569
+ if (!code && !name) return null;
2570
+ return record;
2571
+ }
2572
+ function formatVirtualCurrencyLabel(value, options) {
2573
+ const record = readVirtualCurrencyDefinition(value);
2574
+ if (!record) return "";
2575
+ const code = readString4(record.code);
2576
+ const name = readString4(record.name);
2577
+ if (options?.preferCode && code) return code;
2578
+ if (options?.includeCode && name && code && readLower2(name) !== readLower2(code)) {
2579
+ return `${name} (${code})`;
2580
+ }
2581
+ return name || code;
2582
+ }
2583
+ function formatVirtualCurrencyAmountLabel(input) {
2584
+ const amount = readString4(input.amount);
2585
+ if (!amount) return "";
2586
+ const currencyLabel = formatVirtualCurrencyLabel(input.virtualCurrency);
2587
+ if (currencyLabel) return `${amount} ${currencyLabel}`;
2588
+ const fallbackUnit = readString4(input.fallbackUnit);
2589
+ return fallbackUnit ? `${amount} ${fallbackUnit}` : amount;
2590
+ }
2591
+ function normalizeVirtualCurrencyDisplayLabel(label) {
2592
+ const normalized = readString4(label);
2593
+ if (!normalized) return "";
2594
+ return normalized.replace(/\s+\([^)]+\)\s*$/, "").trim() || normalized;
2182
2595
  }
2183
2596
  function escapeHtml(value) {
2184
2597
  return String(value ?? "").replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
@@ -2188,7 +2601,7 @@ function readRecord(value) {
2188
2601
  return value;
2189
2602
  }
2190
2603
  function formatStateLabel(value, fallback = "\u2014") {
2191
- const raw = readString3(value);
2604
+ const raw = readString4(value);
2192
2605
  if (!raw) return fallback;
2193
2606
  return raw.replace(/_/g, " ");
2194
2607
  }
@@ -2196,8 +2609,8 @@ function hasPositiveCredits(accessProjection) {
2196
2609
  return readNumber(accessProjection?.credits_remaining, 0) > 0;
2197
2610
  }
2198
2611
  function isExhaustedIncludedCreditAccess(input) {
2199
- const balanceState = readLower(input.accessProjection?.balance_state);
2200
- const entitlementState = readLower(input.accessProjection?.entitlement_state);
2612
+ const balanceState = readLower2(input.accessProjection?.balance_state);
2613
+ const entitlementState = readLower2(input.accessProjection?.entitlement_state);
2201
2614
  return !input.currentSubscription && entitlementState === "active" && !hasPositiveCredits(input.accessProjection) && (balanceState === "empty" || balanceState === "insufficient");
2202
2615
  }
2203
2616
  function hasEffectiveCoverage(input) {
@@ -2205,17 +2618,75 @@ function hasEffectiveCoverage(input) {
2205
2618
  return Boolean(input.accessProjection?.has_current_access);
2206
2619
  }
2207
2620
  function formatCoverageLabel(input) {
2621
+ const copy = buildXmsSurfaceCopy({ locale: input.locale });
2208
2622
  if (isExhaustedIncludedCreditAccess(input)) {
2209
2623
  return buildXmsPackageCopy(input.locale).consumedLabel;
2210
2624
  }
2211
- if (hasEffectiveCoverage(input)) return "Available";
2212
- return formatStateLabel(input.accessProjection?.entitlement_state, "Unavailable");
2625
+ if (hasEffectiveCoverage(input)) return copy.coverageActiveLabel;
2626
+ return copy.coverageInactiveLabel;
2627
+ }
2628
+ function resolveSubscriptionCoverageLabel(input) {
2629
+ const copy = buildXmsSurfaceCopy({ locale: input.locale });
2630
+ if (typeof input.overduePolicy?.has_current_access === "boolean") {
2631
+ return input.overduePolicy.has_current_access ? copy.coverageActiveLabel : copy.coverageInactiveLabel;
2632
+ }
2633
+ const status = readLower2(input.currentSubscription?.status);
2634
+ if (status === "active" || status === "trialing" || status === "grace" || status === "cancelled") {
2635
+ return copy.coverageActiveLabel;
2636
+ }
2637
+ if (status === "past_due" || status === "expired" || status === "suspended") {
2638
+ return copy.coverageInactiveLabel;
2639
+ }
2640
+ return "";
2641
+ }
2642
+ function resolveSubscriptionReasonLabel(input) {
2643
+ const copy = buildXmsSurfaceCopy({ locale: input.locale });
2644
+ const reason = readLower2(input.overduePolicy?.effective_status_reason);
2645
+ if (!reason) return "";
2646
+ if (reason === "grace_covered_past_due") return copy.reasonGraceCoveredPastDueLabel;
2647
+ if (reason === "past_due_after_period_end") return copy.reasonPastDueAfterPeriodEndLabel;
2648
+ if (reason === "expired_after_boundary") return copy.reasonExpiredAfterBoundaryLabel;
2649
+ return formatStateLabel(reason, "");
2650
+ }
2651
+ function buildXmsSubscriptionLifecycleSummary(input) {
2652
+ const currentSubscription = readRecord(input.currentSubscription ?? input.current_subscription);
2653
+ const overduePolicy = currentSubscription?.overdue_policy && typeof currentSubscription.overdue_policy === "object" && !Array.isArray(currentSubscription.overdue_policy) ? currentSubscription.overdue_policy : null;
2654
+ const status = readLower2(currentSubscription?.status);
2655
+ const renewsAt = readString4(currentSubscription?.renews_at) || null;
2656
+ const currentPeriodEndsAt = readString4(currentSubscription?.current_period_ends_at) || null;
2657
+ const expiresAt = readString4(currentSubscription?.expired_at) || null;
2658
+ const cancelledAt = readString4(currentSubscription?.cancelled_at) || null;
2659
+ const overdueSince = readString4(overduePolicy?.overdue_since) || null;
2660
+ const expiryBoundaryAt = readString4(overduePolicy?.expiry_boundary_at) || null;
2661
+ return {
2662
+ present: Boolean(currentSubscription),
2663
+ status,
2664
+ statusLabel: formatStateLabel(currentSubscription?.status, ""),
2665
+ coverageLabel: resolveSubscriptionCoverageLabel({
2666
+ currentSubscription,
2667
+ overduePolicy,
2668
+ locale: input.locale
2669
+ }),
2670
+ reasonCode: readString4(overduePolicy?.effective_status_reason) || null,
2671
+ reasonLabel: resolveSubscriptionReasonLabel({
2672
+ overduePolicy,
2673
+ locale: input.locale
2674
+ }),
2675
+ renewsAt,
2676
+ currentPeriodEndsAt,
2677
+ expiresAt,
2678
+ cancelledAt,
2679
+ overdueSince,
2680
+ expiryBoundaryAt,
2681
+ canCancel: Boolean(currentSubscription) && (status === "active" || status === "trialing" || status === "grace" || status === "past_due"),
2682
+ canRefresh: Boolean(currentSubscription)
2683
+ };
2213
2684
  }
2214
2685
  function listXappMonetizationPaywalls(items) {
2215
2686
  return (Array.isArray(items) ? items : []).filter((item) => item && typeof item === "object" && !Array.isArray(item)).map((item) => item);
2216
2687
  }
2217
2688
  function buildPaywallPlacementCandidates(value) {
2218
- const raw = readLower(value);
2689
+ const raw = readLower2(value);
2219
2690
  if (!raw) return [];
2220
2691
  const out = /* @__PURE__ */ new Set([raw]);
2221
2692
  if (raw === "paywall" || raw === "default_paywall") {
@@ -2242,15 +2713,15 @@ function buildPaywallPlacementCandidates(value) {
2242
2713
  }
2243
2714
  function selectXappMonetizationPaywall(input) {
2244
2715
  const paywalls = listXappMonetizationPaywalls(input.paywalls);
2245
- const slug = readLower(input.slug);
2246
- const placement = readLower(input.placement);
2716
+ const slug = readLower2(input.slug);
2717
+ const placement = readLower2(input.placement);
2247
2718
  if (slug) {
2248
- const matched = paywalls.find((item) => readLower(item.slug) === slug);
2719
+ const matched = paywalls.find((item) => readLower2(item.slug) === slug);
2249
2720
  if (matched) return matched;
2250
2721
  }
2251
2722
  if (placement) {
2252
2723
  const candidates = buildPaywallPlacementCandidates(placement);
2253
- const matched = paywalls.find((item) => candidates.includes(readLower(item.placement)));
2724
+ const matched = paywalls.find((item) => candidates.includes(readLower2(item.placement)));
2254
2725
  if (matched) return matched;
2255
2726
  }
2256
2727
  return paywalls[0] || null;
@@ -2262,23 +2733,27 @@ function flattenXappMonetizationPaywallPackages(paywall) {
2262
2733
  const packageRecord = pkg && typeof pkg === "object" && !Array.isArray(pkg) ? pkg : {};
2263
2734
  const price = Array.isArray(packageRecord.prices) ? packageRecord.prices[0] || null : null;
2264
2735
  out.push({
2265
- offeringId: readString3(packageRecord.offering_id),
2266
- offeringSlug: readString3(packageRecord.offering_slug),
2267
- offeringTitle: readString3(packageRecord.offering_slug) || "Offering",
2268
- offeringPlacement: readString3(packageRecord.offering_placement) || null,
2269
- packageId: readString3(packageRecord.id),
2270
- packageSlug: readString3(packageRecord.slug),
2271
- packageTitle: readString3(packageRecord.slug) || "Package",
2272
- packageKind: readString3(packageRecord.package_kind) || "standard",
2273
- productId: readString3(packageRecord.product?.id),
2274
- productSlug: readString3(packageRecord.product?.slug),
2275
- productFamily: readString3(
2736
+ offeringId: readString4(packageRecord.offering_id),
2737
+ offeringSlug: readString4(packageRecord.offering_slug),
2738
+ offeringTitle: readString4(packageRecord.offering_slug) || buildXmsSurfaceCopy().offeringFallbackLabel,
2739
+ offeringPlacement: readString4(packageRecord.offering_placement) || null,
2740
+ packageId: readString4(packageRecord.id),
2741
+ packageSlug: readString4(packageRecord.slug),
2742
+ packageTitle: readString4(packageRecord.slug) || buildXmsSurfaceCopy().packageFallbackLabel,
2743
+ packageKind: readString4(packageRecord.package_kind) || "standard",
2744
+ productId: readString4(packageRecord.product?.id),
2745
+ productSlug: readString4(packageRecord.product?.slug),
2746
+ productFamily: readString4(
2276
2747
  packageRecord.product?.product_family
2277
2748
  ),
2278
- priceId: readString3(price?.id),
2279
- amount: readString3(price?.amount),
2280
- currency: readString3(price?.currency),
2281
- billingPeriod: readString3(price?.billing_period) || null,
2749
+ virtualCurrency: readVirtualCurrencyDefinition(
2750
+ packageRecord.product?.virtual_currency
2751
+ ) ?? null,
2752
+ productMetadata: packageRecord.product?.metadata && typeof packageRecord.product.metadata === "object" ? packageRecord.product.metadata : {},
2753
+ priceId: readString4(price?.id),
2754
+ amount: readString4(price?.amount),
2755
+ currency: readString4(price?.currency),
2756
+ billingPeriod: readString4(price?.billing_period) || null,
2282
2757
  purchasePolicy: readProjectedPurchasePolicy(packageRecord.purchase_policy),
2283
2758
  metadata: packageRecord.metadata && typeof packageRecord.metadata === "object" ? packageRecord.metadata : {}
2284
2759
  });
@@ -2286,7 +2761,7 @@ function flattenXappMonetizationPaywallPackages(paywall) {
2286
2761
  return out.filter((item) => item.offeringId && item.packageId && item.priceId);
2287
2762
  }
2288
2763
  function formatPlacementLabel(value, fallback = "General placement") {
2289
- const raw = readString3(value);
2764
+ const raw = readString4(value);
2290
2765
  if (!raw) return fallback;
2291
2766
  return raw.replace(/[_-]+/g, " ");
2292
2767
  }
@@ -2300,18 +2775,20 @@ function readPackageCredits(item) {
2300
2775
  }
2301
2776
  function buildMonetizationOfferingPresentation(input) {
2302
2777
  const record = input && typeof input === "object" && !Array.isArray(input) ? input : {};
2303
- const offeringLabel = readString3(record.offeringTitle) || formatStateLabel(record.offeringSlug, "Offering");
2304
- const placementRaw = readLower(record.offeringPlacement);
2778
+ const surfaceCopy = buildXmsSurfaceCopy({ locale: record.locale });
2779
+ const offeringLabel = readString4(record.offeringTitle) || formatStateLabel(record.offeringSlug, surfaceCopy.offeringFallbackLabel);
2780
+ const placementRaw = readLower2(record.offeringPlacement);
2305
2781
  const placementLabel = formatPlacementLabel(record.offeringPlacement);
2306
- let summary = "General offering surface for this xapp.";
2782
+ const copy = buildXmsPackageCopy(record.locale);
2783
+ let summary = copy.generalOfferingSummary;
2307
2784
  if (placementRaw.includes("feature") && placementRaw.includes("paywall")) {
2308
- summary = "Feature-paywall placement for gated in-app flows.";
2785
+ summary = copy.featurePaywallOfferingSummary;
2309
2786
  } else if (placementRaw.includes("paywall")) {
2310
- summary = "Default paywall placement for monetized upgrade prompts.";
2787
+ summary = copy.defaultPaywallOfferingSummary;
2311
2788
  } else if (placementRaw.includes("checkout")) {
2312
- summary = "Direct checkout placement for purchase-driven flows.";
2789
+ summary = copy.checkoutOfferingSummary;
2313
2790
  } else if (placementRaw.includes("upgrade")) {
2314
- summary = "Upgrade-oriented placement for membership and package switching.";
2791
+ summary = copy.upgradeOfferingSummary;
2315
2792
  }
2316
2793
  return {
2317
2794
  offeringLabel,
@@ -2321,41 +2798,51 @@ function buildMonetizationOfferingPresentation(input) {
2321
2798
  }
2322
2799
  function buildMonetizationPaywallPresentation(input) {
2323
2800
  const record = input && typeof input === "object" && !Array.isArray(input) ? input : {};
2324
- const paywallLabel = readLocalizedText(record.title, formatStateLabel(record.slug, "Paywall")) || "Paywall";
2801
+ const paywallLabel = readLocalizedText(
2802
+ record.title,
2803
+ formatStateLabel(
2804
+ record.slug,
2805
+ buildXmsSurfaceCopy({ locale: record.locale }).paywallFallbackLabel
2806
+ )
2807
+ ) || buildXmsSurfaceCopy({ locale: record.locale }).paywallFallbackLabel;
2325
2808
  const placementLabel = formatPlacementLabel(record.placement);
2326
2809
  const packages = flattenXappMonetizationPaywallPackages(record);
2327
- const defaultPackageRef = readString3(record.default_package_ref);
2328
- const defaultPackage = packages.find((item) => readString3(item.packageSlug) === defaultPackageRef) || packages[0] || null;
2810
+ const defaultPackageRef = readString4(record.default_package_ref);
2811
+ const defaultPackage = packages.find((item) => readString4(item.packageSlug) === defaultPackageRef) || packages[0] || null;
2329
2812
  const summary = readLocalizedText(record.description) || (placementLabel === "General placement" ? "Presentation surface for monetized package selection." : `${placementLabel} surface for monetized package selection.`);
2330
2813
  return {
2331
2814
  paywallLabel,
2332
2815
  placementLabel,
2333
2816
  summary,
2334
- defaultPackageLabel: defaultPackage ? readString3(defaultPackage.packageTitle) : "",
2817
+ defaultPackageLabel: defaultPackage ? readString4(defaultPackage.packageTitle) : "",
2335
2818
  packageCountLabel: `${packages.length} package${packages.length === 1 ? "" : "s"}`
2336
2819
  };
2337
2820
  }
2338
2821
  function buildMonetizationPaywallRenderModel(input) {
2339
2822
  const record = input && typeof input === "object" && !Array.isArray(input) ? input : {};
2340
2823
  const presentation = buildMonetizationPaywallPresentation(record);
2341
- const defaultPackageRef = readString3(record.default_package_ref);
2824
+ const defaultPackageRef = readString4(record.default_package_ref);
2342
2825
  const packages = flattenXappMonetizationPaywallPackages(record).map((item) => {
2343
2826
  const packagePresentation = buildMonetizationPackagePresentation(item);
2344
2827
  return {
2345
- packageId: readString3(item.packageId),
2346
- packageSlug: readString3(item.packageSlug),
2347
- packageTitle: readString3(item.packageTitle) || "Package",
2348
- productId: readString3(item.productId),
2349
- productSlug: readString3(item.productSlug),
2350
- productFamily: readString3(item.productFamily),
2828
+ packageId: readString4(item.packageId),
2829
+ packageSlug: readString4(item.packageSlug),
2830
+ packageTitle: readString4(item.packageTitle) || buildXmsSurfaceCopy().packageFallbackLabel,
2831
+ productId: readString4(item.productId),
2832
+ productSlug: readString4(item.productSlug),
2833
+ productFamily: readString4(item.productFamily),
2834
+ virtualCurrencyCode: formatVirtualCurrencyLabel(item.virtualCurrency, { preferCode: true }),
2835
+ virtualCurrencyName: formatVirtualCurrencyLabel(item.virtualCurrency),
2836
+ virtualCurrencyLabel: formatVirtualCurrencyLabel(item.virtualCurrency, { includeCode: true }),
2837
+ productMetadata: item.productMetadata && typeof item.productMetadata === "object" && !Array.isArray(item.productMetadata) ? item.productMetadata : {},
2351
2838
  metadata: item.metadata && typeof item.metadata === "object" && !Array.isArray(item.metadata) ? item.metadata : {},
2352
- description: readString3(item.description) || packagePresentation.summary,
2839
+ description: readString4(item.description) || packagePresentation.summary,
2353
2840
  fitLabel: packagePresentation.fitLabel,
2354
2841
  moneyLabel: packagePresentation.moneyLabel,
2355
2842
  offeringLabel: packagePresentation.offeringLabel,
2356
2843
  placementLabel: packagePresentation.placementLabel,
2357
2844
  signals: packagePresentation.signals,
2358
- isDefault: Boolean(defaultPackageRef) && readString3(item.packageSlug) === defaultPackageRef
2845
+ isDefault: Boolean(defaultPackageRef) && readString4(item.packageSlug) === defaultPackageRef
2359
2846
  };
2360
2847
  });
2361
2848
  const badges = [presentation.placementLabel, presentation.packageCountLabel];
@@ -2415,6 +2902,11 @@ var monetizationPlansSurfaceStyles = `
2415
2902
  display: grid;
2416
2903
  gap: 10px;
2417
2904
  }
2905
+ .xapps-xms-plans__surface-actions {
2906
+ display: flex;
2907
+ flex-wrap: wrap;
2908
+ gap: 10px;
2909
+ }
2418
2910
  .xapps-xms-plans__meta-row {
2419
2911
  display: flex;
2420
2912
  justify-content: space-between;
@@ -2558,6 +3050,42 @@ var monetizationPlansSurfaceStyles = `
2558
3050
  transform: none;
2559
3051
  box-shadow: none;
2560
3052
  }
3053
+ .xapps-xms-plans__surface-action {
3054
+ min-height: 38px;
3055
+ border-radius: 12px;
3056
+ padding: 9px 13px;
3057
+ border: 1px solid color-mix(in srgb, var(--xapps-border-color, rgba(148, 163, 184, 0.24)) 92%, transparent);
3058
+ background: color-mix(in srgb, var(--xapps-surface-bg, #ffffff) 96%, var(--xapps-surface-subtle, #f8fafc));
3059
+ color: var(--xapps-text-primary, #0f172a);
3060
+ font-weight: 700;
3061
+ cursor: pointer;
3062
+ transition:
3063
+ border-color 0.18s ease,
3064
+ background-color 0.18s ease,
3065
+ color 0.18s ease,
3066
+ box-shadow 0.18s ease;
3067
+ }
3068
+ .xapps-xms-plans__surface-action:hover,
3069
+ .xapps-xms-plans__surface-action:focus-visible {
3070
+ border-color: color-mix(in srgb, var(--xapps-accent, #0f766e) 28%, var(--xapps-border-color, transparent));
3071
+ background: color-mix(in srgb, var(--xapps-accent, #0f766e) 7%, var(--xapps-surface-bg, #ffffff));
3072
+ color: color-mix(in srgb, var(--xapps-accent, #0f766e) 24%, var(--xapps-text-primary, #0f172a));
3073
+ }
3074
+ .xapps-xms-plans__surface-action[data-variant="danger"] {
3075
+ border-color: color-mix(in srgb, var(--xapps-danger, #dc2626) 22%, var(--xapps-border-color, transparent));
3076
+ color: var(--xapps-danger, #b91c1c);
3077
+ }
3078
+ .xapps-xms-plans__surface-action[data-variant="danger"]:hover,
3079
+ .xapps-xms-plans__surface-action[data-variant="danger"]:focus-visible {
3080
+ border-color: color-mix(in srgb, var(--xapps-danger, #dc2626) 34%, var(--xapps-border-color, transparent));
3081
+ background: color-mix(in srgb, var(--xapps-danger, #dc2626) 8%, var(--xapps-surface-bg, #ffffff));
3082
+ color: var(--xapps-danger, #991b1b);
3083
+ }
3084
+ .xapps-xms-plans__surface-action[disabled] {
3085
+ cursor: not-allowed;
3086
+ opacity: 0.6;
3087
+ box-shadow: none;
3088
+ }
2561
3089
  .xapps-xms-plans__empty {
2562
3090
  color: var(--xapps-text-secondary, #64748b);
2563
3091
  font-size: 14px;
@@ -2655,7 +3183,7 @@ var monetizationPlansSurfaceStyles = `
2655
3183
  }
2656
3184
  `;
2657
3185
  function formatPlansDateTime(value, locale = "en") {
2658
- const raw = readString3(value);
3186
+ const raw = readString4(value);
2659
3187
  if (!raw) return "";
2660
3188
  const parsed = new Date(raw);
2661
3189
  if (Number.isNaN(parsed.getTime())) return raw;
@@ -2681,9 +3209,98 @@ function readHistoryBucket(history, key) {
2681
3209
  items
2682
3210
  };
2683
3211
  }
3212
+ function formatBalanceQuantity(value) {
3213
+ if (!Number.isFinite(value)) return "";
3214
+ const normalized = Math.round(value * 1e4) / 1e4;
3215
+ if (Number.isInteger(normalized)) return String(normalized);
3216
+ return normalized.toFixed(4).replace(/\.?0+$/, "");
3217
+ }
3218
+ function summarizeVirtualCurrencyBalances(input) {
3219
+ const record = readRecord(input) ?? {};
3220
+ const history = readRecord(record.history) ?? record;
3221
+ const walletAccounts = readHistoryBucket(history, "wallet_accounts").items;
3222
+ const accessSnapshots = readHistoryBucket(history, "access_snapshots").items;
3223
+ const aggregates = /* @__PURE__ */ new Map();
3224
+ const upsertBalance = (inputValue) => {
3225
+ const amount = readNumber(inputValue.amount, Number.NaN);
3226
+ if (!Number.isFinite(amount) || Math.abs(amount) < 1e-7) return;
3227
+ const label = formatVirtualCurrencyLabel(inputValue.virtualCurrency, {
3228
+ includeCode: true
3229
+ }) || readString4(inputValue.fallbackUnit) || readString4(inputValue.fallbackKey) || "Balance";
3230
+ const key = formatVirtualCurrencyLabel(inputValue.virtualCurrency, {
3231
+ preferCode: true
3232
+ }) || readString4(inputValue.fallbackKey) || label.toLowerCase();
3233
+ const existing = aggregates.get(key);
3234
+ if (existing) {
3235
+ existing.amount += amount;
3236
+ existing.accountCount += 1;
3237
+ return;
3238
+ }
3239
+ aggregates.set(key, {
3240
+ label,
3241
+ amount,
3242
+ accountCount: 1,
3243
+ virtualCurrency: inputValue.virtualCurrency ?? null,
3244
+ fallbackUnit: readString4(inputValue.fallbackUnit)
3245
+ });
3246
+ };
3247
+ for (const item of walletAccounts) {
3248
+ upsertBalance({
3249
+ amount: item.balance_remaining,
3250
+ virtualCurrency: item.virtual_currency,
3251
+ fallbackUnit: item.currency,
3252
+ fallbackKey: item.product_slug || item.id
3253
+ });
3254
+ }
3255
+ if (aggregates.size === 0 && accessSnapshots.length > 0) {
3256
+ for (const item of accessSnapshots) {
3257
+ upsertBalance({
3258
+ amount: item.credits_remaining,
3259
+ virtualCurrency: item.virtual_currency,
3260
+ fallbackUnit: "credits",
3261
+ fallbackKey: item.tier || item.id
3262
+ });
3263
+ }
3264
+ }
3265
+ const balances = Array.from(aggregates.entries()).map(([key, item]) => {
3266
+ const amount = formatBalanceQuantity(item.amount);
3267
+ return {
3268
+ key,
3269
+ label: item.label,
3270
+ amount,
3271
+ amountLabel: formatVirtualCurrencyAmountLabel({
3272
+ amount,
3273
+ virtualCurrency: item.virtualCurrency,
3274
+ fallbackUnit: item.fallbackUnit
3275
+ }) || amount,
3276
+ accountCount: item.accountCount
3277
+ };
3278
+ }).sort((left, right) => {
3279
+ const amountDiff = readNumber(right.amount) - readNumber(left.amount);
3280
+ if (Math.abs(amountDiff) > 1e-7) return amountDiff > 0 ? 1 : -1;
3281
+ return left.label.localeCompare(right.label);
3282
+ });
3283
+ return {
3284
+ balances,
3285
+ totalAccounts: walletAccounts.length,
3286
+ totalCurrencies: balances.length
3287
+ };
3288
+ }
2684
3289
  function readHistoryTitle(item, keys, fallback) {
2685
3290
  for (const key of keys) {
2686
- const value = readString3(item[key]);
3291
+ const segments = key.split(".");
3292
+ let current = item;
3293
+ for (const segment of segments) {
3294
+ const record = readRecord(current);
3295
+ current = record ? record[segment] : void 0;
3296
+ }
3297
+ if (key.startsWith("virtual_currency.")) {
3298
+ const value2 = formatVirtualCurrencyLabel(item.virtual_currency ?? current, {
3299
+ includeCode: true
3300
+ });
3301
+ if (value2) return value2;
3302
+ }
3303
+ const value = readString4(current);
2687
3304
  if (value) return value;
2688
3305
  }
2689
3306
  return fallback;
@@ -2691,13 +3308,31 @@ function readHistoryTitle(item, keys, fallback) {
2691
3308
  function readHistoryMeta(item, keys, locale) {
2692
3309
  const out = [];
2693
3310
  for (const key of keys) {
2694
- const value = key.endsWith("_at") ? formatPlansDateTime(item[key], locale) : readString3(item[key]);
3311
+ const segments = key.split(".");
3312
+ let current = item;
3313
+ for (const segment of segments) {
3314
+ const record = readRecord(current);
3315
+ current = record ? record[segment] : void 0;
3316
+ }
3317
+ const value = key === "settlement_effect_detail" ? formatSettlementEffectDetailLabel(item.settlement_effect, current, locale) : key === "balance_remaining" ? formatVirtualCurrencyAmountLabel({
3318
+ amount: current,
3319
+ virtualCurrency: item.virtual_currency,
3320
+ fallbackUnit: readString4(item.currency)
3321
+ }) : key === "amount" ? formatVirtualCurrencyAmountLabel({
3322
+ amount: current,
3323
+ virtualCurrency: item.virtual_currency,
3324
+ fallbackUnit: readString4(item.currency)
3325
+ }) : key === "credits_remaining" ? formatVirtualCurrencyAmountLabel({
3326
+ amount: current,
3327
+ virtualCurrency: item.virtual_currency,
3328
+ fallbackUnit: "credits"
3329
+ }) : key.endsWith("_at") ? formatPlansDateTime(current, locale) : readString4(current);
2695
3330
  if (value) out.push(formatStateLabel(value, value));
2696
3331
  }
2697
3332
  return out;
2698
3333
  }
2699
3334
  function formatTimelineBucketLabel(value, locale) {
2700
- const normalized = readLower(value);
3335
+ const normalized = readLower2(value);
2701
3336
  const copy = buildXmsSurfaceCopy({ locale });
2702
3337
  if (!normalized) return copy.historyGenericLabel;
2703
3338
  if (normalized === "purchase_intents") return copy.historyPurchaseIntentLabel;
@@ -2709,20 +3344,70 @@ function formatTimelineBucketLabel(value, locale) {
2709
3344
  if (normalized === "invoices") return copy.historyInvoiceLabel;
2710
3345
  return formatStateLabel(normalized, normalized);
2711
3346
  }
3347
+ function formatSettlementEffectDetailLabel(effect, detail, locale) {
3348
+ const rawDetail = readString4(detail);
3349
+ if (!rawDetail) return null;
3350
+ const normalizedEffect = readLower2(effect);
3351
+ const normalizedDetail = readLower2(detail);
3352
+ const copy = buildXmsSurfaceCopy({ locale });
3353
+ if (normalizedEffect === "transaction_chargeback") {
3354
+ if (normalizedDetail === "warning_needs_response") {
3355
+ return copy.historySettlementDetailDisputeWarningNeedsResponse;
3356
+ }
3357
+ if (normalizedDetail === "warning_under_review") {
3358
+ return copy.historySettlementDetailDisputeWarningUnderReview;
3359
+ }
3360
+ if (normalizedDetail === "warning_closed") {
3361
+ return copy.historySettlementDetailDisputeWarningClosed;
3362
+ }
3363
+ if (normalizedDetail === "needs_response") {
3364
+ return copy.historySettlementDetailDisputeNeedsResponse;
3365
+ }
3366
+ if (normalizedDetail === "under_review") {
3367
+ return copy.historySettlementDetailDisputeUnderReview;
3368
+ }
3369
+ if (normalizedDetail === "won") {
3370
+ return copy.historySettlementDetailDisputeWon;
3371
+ }
3372
+ if (normalizedDetail === "lost") {
3373
+ return copy.historySettlementDetailDisputeLost;
3374
+ }
3375
+ return normalizedDetail.replace(/_/g, " ");
3376
+ }
3377
+ return rawDetail;
3378
+ }
2712
3379
  function buildTimelineHtml(input) {
2713
3380
  if (!input.total) return "";
3381
+ const items = [...input.items].sort((left, right) => {
3382
+ const leftAt = Date.parse(readString4(left.occurred_at));
3383
+ const rightAt = Date.parse(readString4(right.occurred_at));
3384
+ if (Number.isFinite(leftAt) && Number.isFinite(rightAt) && leftAt !== rightAt) {
3385
+ return rightAt - leftAt;
3386
+ }
3387
+ return readString4(right.id).localeCompare(readString4(left.id));
3388
+ });
2714
3389
  return `
2715
3390
  <div class="xapps-xms-plans__timeline">
2716
- ${input.items.map((item) => {
2717
- const title = readString3(item.title) || readString3(item.id) || formatTimelineBucketLabel(item.bucket, input.locale);
3391
+ ${items.map((item) => {
3392
+ const title = readString4(item.title) || readString4(item.id) || formatTimelineBucketLabel(item.bucket, input.locale);
2718
3393
  const when = formatPlansDateTime(item.occurred_at, input.locale);
2719
3394
  const meta = [
2720
3395
  formatTimelineBucketLabel(item.bucket, input.locale),
2721
- readString3(item.status) ? formatStateLabel(item.status, readString3(item.status)) : "",
2722
- readString3(item.scope),
2723
- readString3(item.correlation),
2724
- readString3(item.amount) && readString3(item.currency) ? `${readString3(item.amount)} ${readString3(item.currency)}` : readString3(item.amount),
2725
- readString3(item.note)
3396
+ readString4(item.status) ? formatStateLabel(item.status, readString4(item.status)) : "",
3397
+ readString4(item.settlement_effect) ? formatStateLabel(item.settlement_effect, readString4(item.settlement_effect)) : "",
3398
+ formatSettlementEffectDetailLabel(
3399
+ item.settlement_effect,
3400
+ item.settlement_effect_detail,
3401
+ input.locale
3402
+ ),
3403
+ readString4(item.scope),
3404
+ readString4(item.correlation),
3405
+ formatVirtualCurrencyAmountLabel({
3406
+ amount: item.amount,
3407
+ virtualCurrency: item.virtual_currency,
3408
+ fallbackUnit: readString4(item.currency)
3409
+ }),
3410
+ readString4(item.note)
2726
3411
  ].filter(Boolean);
2727
3412
  return `
2728
3413
  <div class="xapps-xms-plans__timeline-item">
@@ -2749,7 +3434,7 @@ function buildHistorySectionHtml(input) {
2749
3434
  ${input.items.map((item) => {
2750
3435
  const title = readHistoryTitle(item, input.itemTitleKeys, input.itemFallbackTitle);
2751
3436
  const statusKeys = input.itemStatusKeys || [];
2752
- const status = statusKeys.map((key) => readString3(item[key])).find(Boolean);
3437
+ const status = statusKeys.map((key) => readString4(item[key])).find(Boolean);
2753
3438
  const meta = readHistoryMeta(item, input.itemMetaKeys, input.locale);
2754
3439
  return `
2755
3440
  <div class="xapps-xms-plans__history-item">
@@ -2773,26 +3458,6 @@ function buildMonetizationHistorySections(input) {
2773
3458
  const { history, locale } = input;
2774
3459
  const copy = buildXmsSurfaceCopy({ locale });
2775
3460
  return [
2776
- buildHistorySectionHtml({
2777
- title: copy.historyPurchaseIntentsTitle,
2778
- total: readHistoryBucket(history, "purchase_intents").total,
2779
- items: readHistoryBucket(history, "purchase_intents").items,
2780
- locale,
2781
- itemTitleKeys: ["package_slug", "product_slug", "id"],
2782
- itemFallbackTitle: copy.historyPurchaseIntentLabel,
2783
- itemStatusKeys: ["status"],
2784
- itemMetaKeys: ["amount", "currency", "payment_lane", "updated_at"]
2785
- }),
2786
- buildHistorySectionHtml({
2787
- title: copy.historyTransactionsTitle,
2788
- total: readHistoryBucket(history, "transactions").total,
2789
- items: readHistoryBucket(history, "transactions").items,
2790
- locale,
2791
- itemTitleKeys: ["package_slug", "product_slug", "id"],
2792
- itemFallbackTitle: copy.historyTransactionLabel,
2793
- itemStatusKeys: ["status"],
2794
- itemMetaKeys: ["amount", "currency", "payment_session_id", "occurred_at"]
2795
- }),
2796
3461
  buildHistorySectionHtml({
2797
3462
  title: copy.historySubscriptionsTitle,
2798
3463
  total: readHistoryBucket(history, "subscriptions").total,
@@ -2818,30 +3483,46 @@ function buildMonetizationHistorySections(input) {
2818
3483
  total: readHistoryBucket(history, "wallet_accounts").total,
2819
3484
  items: readHistoryBucket(history, "wallet_accounts").items,
2820
3485
  locale,
2821
- itemTitleKeys: ["product_slug", "id"],
3486
+ itemTitleKeys: ["virtual_currency.code", "product_slug", "id"],
2822
3487
  itemFallbackTitle: copy.historyWalletAccountLabel,
2823
3488
  itemStatusKeys: ["status"],
2824
- itemMetaKeys: ["currency", "balance_remaining", "updated_at"]
3489
+ itemMetaKeys: ["balance_remaining", "updated_at"]
2825
3490
  }),
2826
3491
  buildHistorySectionHtml({
2827
3492
  title: copy.historyWalletLedgerTitle,
2828
3493
  total: readHistoryBucket(history, "wallet_ledger").total,
2829
3494
  items: readHistoryBucket(history, "wallet_ledger").items,
2830
3495
  locale,
2831
- itemTitleKeys: ["event_kind", "wallet_product_slug", "id"],
3496
+ itemTitleKeys: ["event_kind", "virtual_currency.code", "wallet_product_slug", "id"],
2832
3497
  itemFallbackTitle: copy.historyWalletLedgerEntryLabel,
2833
3498
  itemStatusKeys: [],
2834
- itemMetaKeys: ["amount", "currency", "source_kind", "occurred_at"]
3499
+ itemMetaKeys: ["amount", "settlement_effect", "source_kind", "occurred_at"]
2835
3500
  }),
2836
3501
  buildHistorySectionHtml({
2837
- title: copy.historyAccessSnapshotsTitle,
2838
- total: readHistoryBucket(history, "access_snapshots").total,
2839
- items: readHistoryBucket(history, "access_snapshots").items,
3502
+ title: copy.historyTransactionsTitle,
3503
+ total: readHistoryBucket(history, "transactions").total,
3504
+ items: readHistoryBucket(history, "transactions").items,
2840
3505
  locale,
2841
- itemTitleKeys: ["tier", "id"],
2842
- itemFallbackTitle: copy.historyAccessSnapshotLabel,
2843
- itemStatusKeys: ["entitlement_state"],
2844
- itemMetaKeys: ["balance_state", "credits_remaining", "updated_at"]
3506
+ itemTitleKeys: ["package_slug", "product_slug", "id"],
3507
+ itemFallbackTitle: copy.historyTransactionLabel,
3508
+ itemStatusKeys: ["status"],
3509
+ itemMetaKeys: [
3510
+ "amount",
3511
+ "currency",
3512
+ "settlement_effect",
3513
+ "payment_session_id",
3514
+ "occurred_at"
3515
+ ]
3516
+ }),
3517
+ buildHistorySectionHtml({
3518
+ title: copy.historyPurchaseIntentsTitle,
3519
+ total: readHistoryBucket(history, "purchase_intents").total,
3520
+ items: readHistoryBucket(history, "purchase_intents").items,
3521
+ locale,
3522
+ itemTitleKeys: ["package_slug", "product_slug", "id"],
3523
+ itemFallbackTitle: copy.historyPurchaseIntentLabel,
3524
+ itemStatusKeys: ["status"],
3525
+ itemMetaKeys: ["amount", "currency", "payment_lane", "updated_at"]
2845
3526
  }),
2846
3527
  buildHistorySectionHtml({
2847
3528
  title: copy.historyInvoicesTitle,
@@ -2851,36 +3532,68 @@ function buildMonetizationHistorySections(input) {
2851
3532
  itemTitleKeys: ["invoice_identifier", "id"],
2852
3533
  itemFallbackTitle: copy.historyInvoiceLabel,
2853
3534
  itemStatusKeys: ["status"],
2854
- itemMetaKeys: ["provider_key", "owner_scope", "created_at"]
3535
+ itemMetaKeys: [
3536
+ "settlement_effect",
3537
+ "settlement_effect_detail",
3538
+ "provider_key",
3539
+ "owner_scope",
3540
+ "created_at"
3541
+ ]
3542
+ }),
3543
+ buildHistorySectionHtml({
3544
+ title: copy.historyAccessSnapshotsTitle,
3545
+ total: readHistoryBucket(history, "access_snapshots").total,
3546
+ items: readHistoryBucket(history, "access_snapshots").items,
3547
+ locale,
3548
+ itemTitleKeys: ["tier", "id"],
3549
+ itemFallbackTitle: copy.historyAccessSnapshotLabel,
3550
+ itemStatusKeys: ["entitlement_state"],
3551
+ itemMetaKeys: ["balance_state", "credits_remaining", "updated_at"]
2855
3552
  })
2856
3553
  ].filter(Boolean);
2857
3554
  }
2858
- function buildXmsSurfaceCopy(input) {
2859
- return XMS_COPY_CATALOG[resolveXmsCopyLocale(input?.locale)].surface;
3555
+ function buildMonetizationHistoryBalanceSummaryHtml(input) {
3556
+ const { history, locale } = input;
3557
+ const copy = buildXmsSurfaceCopy({ locale });
3558
+ const summary = summarizeVirtualCurrencyBalances(history);
3559
+ if (!summary.balances.length) return "";
3560
+ return `
3561
+ <section class="xapps-xms-plans__card">
3562
+ <h4 class="xapps-xms-plans__section-title">${escapeHtml(copy.historyBalanceSummaryTitle)}</h4>
3563
+ <div class="xapps-xms-plans__subtitle">${escapeHtml(copy.historyBalanceSummarySubtitle)}</div>
3564
+ <div class="xapps-xms-plans__badges">
3565
+ ${summary.balances.map(
3566
+ (item) => `<span class="xapps-xms-plans__badge">${escapeHtml(item.amountLabel)}</span>`
3567
+ ).join("")}
3568
+ </div>
3569
+ </section>
3570
+ `;
2860
3571
  }
2861
3572
  function buildMonetizationHistorySurfaceHtml(input, options = {}) {
2862
3573
  const record = readRecord(input) ?? {};
2863
3574
  const history = readRecord(record.history) ?? record;
2864
- const locale = readString3(options.locale) || "en";
3575
+ const locale = readString4(options.locale) || "en";
2865
3576
  const includeStyles = options.includeStyles !== false;
2866
3577
  const showHeader = options.showHeader !== false;
2867
3578
  const surfaceCopy = buildXmsSurfaceCopy({ locale });
2868
3579
  const historySections = buildMonetizationHistorySections({ history, locale });
3580
+ const balanceSummaryHtml = buildMonetizationHistoryBalanceSummaryHtml({ history, locale });
2869
3581
  const timeline = readHistoryBucket(history, "timeline");
2870
- const hasHistory = timeline.total || historySections.length;
3582
+ const hasHistory = Boolean(timeline.total || historySections.length || balanceSummaryHtml);
2871
3583
  return `
2872
3584
  ${includeStyles ? `<style>${monetizationPlansSurfaceStyles}</style>` : ""}
2873
3585
  <section class="xapps-xms-plans">
2874
3586
  ${showHeader ? `<div class="xapps-xms-plans__header">
2875
3587
  <h3 class="xapps-xms-plans__title">${escapeHtml(
2876
- readString3(options.title) || surfaceCopy.historyTitle
3588
+ readString4(options.title) || surfaceCopy.historyTitle
2877
3589
  )}</h3>
2878
- ${readString3(options.subtitle) ? `<div class="xapps-xms-plans__subtitle">${escapeHtml(
2879
- readString3(options.subtitle)
3590
+ ${readString4(options.subtitle) ? `<div class="xapps-xms-plans__subtitle">${escapeHtml(
3591
+ readString4(options.subtitle)
2880
3592
  )}</div>` : ""}
2881
3593
  </div>` : ""}
2882
- ${readString3(options.notice) ? `<div class="xapps-xms-plans__notice">${escapeHtml(readString3(options.notice))}</div>` : ""}
2883
- ${readString3(options.error) ? `<div class="xapps-xms-plans__error">${escapeHtml(readString3(options.error))}</div>` : ""}
3594
+ ${readString4(options.notice) ? `<div class="xapps-xms-plans__notice">${escapeHtml(readString4(options.notice))}</div>` : ""}
3595
+ ${readString4(options.error) ? `<div class="xapps-xms-plans__error">${escapeHtml(readString4(options.error))}</div>` : ""}
3596
+ ${balanceSummaryHtml}
2884
3597
  ${timeline.total ? `<section class="xapps-xms-plans__card">
2885
3598
  <h4 class="xapps-xms-plans__section-title">${escapeHtml(surfaceCopy.recentTimelineTitle)}</h4>
2886
3599
  <div class="xapps-xms-plans__subtitle">${escapeHtml(surfaceCopy.recentTimelineSubtitle)}</div>
@@ -2903,43 +3616,64 @@ function buildMonetizationHistorySurfaceHtml(input, options = {}) {
2903
3616
  }
2904
3617
  function buildMonetizationPackagePresentation(input) {
2905
3618
  const item = input && typeof input === "object" && !Array.isArray(input) ? input : {};
2906
- const packageKind = readString3(item.packageKind);
2907
- const packageSlug = readLower(item.packageSlug);
3619
+ const copy = buildXmsPackageCopy(item.locale);
3620
+ const packageKind = readString4(item.packageKind);
3621
+ const packageSlug = readLower2(item.packageSlug);
2908
3622
  const metadata = item.metadata && typeof item.metadata === "object" && !Array.isArray(item.metadata) ? item.metadata : {};
2909
3623
  const credits = readPackageCredits(item);
3624
+ const virtualCurrency = readVirtualCurrencyDefinition(item.virtualCurrency) ?? readVirtualCurrencyDefinition(
3625
+ item.productMetadata && typeof item.productMetadata === "object" ? item.productMetadata.virtual_currency : null
3626
+ );
2910
3627
  const moneyLabel = normalizeMoneyLabel(item);
2911
3628
  const offeringPresentation = buildMonetizationOfferingPresentation(item);
2912
- let fitLabel = "General upgrade";
2913
- let summary = "Useful as a general monetization upgrade for this creator scope.";
3629
+ let fitLabel = copy.generalUpgradeFitLabel;
3630
+ let summary = copy.generalUpgradeSummary;
2914
3631
  if (packageKind === "one_time_unlock") {
2915
- fitLabel = "Durable unlock";
2916
- summary = "Best when the feature mainly needs current access without ongoing membership.";
3632
+ fitLabel = copy.durableUnlockFitLabel;
3633
+ summary = copy.durableUnlockSummary;
2917
3634
  } else if (packageKind === "subscription") {
2918
- fitLabel = "Recurring membership";
2919
- summary = "Best when the feature depends on ongoing membership coverage.";
3635
+ fitLabel = copy.recurringMembershipFitLabel;
3636
+ summary = copy.recurringMembershipSummary;
2920
3637
  } else if (packageKind === "credit_pack") {
2921
- fitLabel = "Credit top-up";
2922
- summary = "Best when the feature spends credits for each advanced action.";
3638
+ const unitLabel = normalizeVirtualCurrencyDisplayLabel(
3639
+ formatVirtualCurrencyLabel(virtualCurrency, { includeCode: true })
3640
+ );
3641
+ fitLabel = copy.creditTopUpFitLabel;
3642
+ summary = copy.creditPackFitSummary(unitLabel || "credits");
2923
3643
  } else if (packageSlug.includes("hybrid")) {
2924
- fitLabel = "Hybrid upgrade";
2925
- summary = "Blends access coverage with bundled credits for mixed workflows.";
3644
+ const unitLabel = normalizeVirtualCurrencyDisplayLabel(
3645
+ formatVirtualCurrencyLabel(virtualCurrency, { includeCode: true })
3646
+ );
3647
+ fitLabel = copy.hybridUpgradeFitLabel;
3648
+ summary = copy.hybridPackFitSummary(unitLabel || "credits");
2926
3649
  }
2927
3650
  const signals = [];
2928
- if (readString3(metadata.badge)) {
2929
- signals.push(readString3(metadata.badge));
2930
- }
2931
- if (credits > 0) {
3651
+ if (readString4(metadata.badge)) {
3652
+ signals.push(readString4(metadata.badge));
3653
+ }
3654
+ if (credits > 0 && virtualCurrency) {
3655
+ signals.push(
3656
+ formatVirtualCurrencyAmountLabel({
3657
+ amount: String(credits),
3658
+ virtualCurrency,
3659
+ fallbackUnit: "credits"
3660
+ })
3661
+ );
3662
+ } else if (credits > 0) {
2932
3663
  signals.push(`${credits} credits`);
3664
+ } else if (virtualCurrency) {
3665
+ signals.push(
3666
+ copy.packageCurrencySignalLabel(
3667
+ formatVirtualCurrencyLabel(virtualCurrency, { includeCode: true })
3668
+ )
3669
+ );
2933
3670
  }
2934
- if (readString3(item.billingPeriod)) {
2935
- signals.push(`billed ${readString3(item.billingPeriod)}`);
3671
+ if (readString4(item.billingPeriod)) {
3672
+ signals.push(copy.billedSignalLabel(readString4(item.billingPeriod)));
2936
3673
  }
2937
3674
  if (offeringPresentation.offeringLabel) {
2938
3675
  signals.push(offeringPresentation.offeringLabel);
2939
3676
  }
2940
- if (offeringPresentation.placementLabel && offeringPresentation.placementLabel !== "General placement") {
2941
- signals.push(offeringPresentation.placementLabel);
2942
- }
2943
3677
  return {
2944
3678
  fitLabel,
2945
3679
  summary,
@@ -2952,26 +3686,39 @@ function buildMonetizationPackagePresentation(input) {
2952
3686
  }
2953
3687
  function collectPackageOwnershipCandidates(item) {
2954
3688
  const metadata = item.metadata && typeof item.metadata === "object" && !Array.isArray(item.metadata) ? item.metadata : {};
3689
+ const productMetadata = item.productMetadata && typeof item.productMetadata === "object" && !Array.isArray(item.productMetadata) ? item.productMetadata : {};
3690
+ return [
3691
+ readLower2(item.productSlug),
3692
+ readLower2(item.packageSlug),
3693
+ readLower2(metadata.tier),
3694
+ readLower2(metadata.access_tier),
3695
+ readLower2(productMetadata.tier),
3696
+ readLower2(productMetadata.access_tier)
3697
+ ].filter(Boolean);
3698
+ }
3699
+ function collectCurrentSubscriptionCandidates(currentSubscription) {
3700
+ const metadata = currentSubscription.metadata && typeof currentSubscription.metadata === "object" ? currentSubscription.metadata : currentSubscription.metadata_jsonb && typeof currentSubscription.metadata_jsonb === "object" ? currentSubscription.metadata_jsonb : {};
2955
3701
  return [
2956
- readLower(item.productSlug),
2957
- readLower(item.packageSlug),
2958
- readLower(metadata.tier),
2959
- readLower(metadata.access_tier)
3702
+ readLower2(currentSubscription.product_slug),
3703
+ readLower2(currentSubscription.tier),
3704
+ readLower2(metadata.product_slug),
3705
+ readLower2(metadata.tier),
3706
+ readLower2(metadata.access_tier)
2960
3707
  ].filter(Boolean);
2961
3708
  }
2962
3709
  function hasActiveRecurringSubscription(currentSubscription) {
2963
3710
  const record = currentSubscription && typeof currentSubscription === "object" && !Array.isArray(currentSubscription) ? currentSubscription : {};
2964
- const status = readLower(record.status);
3711
+ const status = readLower2(record.status);
2965
3712
  if (!status || status === "expired") return false;
2966
- const expiredAt = readString3(record.expired_at);
3713
+ const expiredAt = readString4(record.expired_at);
2967
3714
  if (!expiredAt) return true;
2968
3715
  const expiresAtMs = Date.parse(expiredAt);
2969
3716
  return Number.isNaN(expiresAtMs) || expiresAtMs > Date.now();
2970
3717
  }
2971
3718
  function hasCurrentOwnedEntitlement(entitlement) {
2972
- const status = readLower(entitlement.status);
3719
+ const status = readLower2(entitlement.status);
2973
3720
  if (status !== "active" && status !== "grace_period") return false;
2974
- const expiresAt = readString3(entitlement.expires_at);
3721
+ const expiresAt = readString4(entitlement.expires_at);
2975
3722
  if (!expiresAt) return true;
2976
3723
  const expiresAtMs = Date.parse(expiresAt);
2977
3724
  return Number.isNaN(expiresAtMs) || expiresAtMs > Date.now();
@@ -2979,14 +3726,14 @@ function hasCurrentOwnedEntitlement(entitlement) {
2979
3726
  function readProjectedPurchasePolicy(value) {
2980
3727
  const record = value && typeof value === "object" && !Array.isArray(value) ? value : null;
2981
3728
  if (!record) return null;
2982
- const status = readLower(record.status);
2983
- const transitionKind = readLower(record.transition_kind ?? record.transitionKind);
3729
+ const status = readLower2(record.status);
3730
+ const transitionKind = readLower2(record.transition_kind ?? record.transitionKind);
2984
3731
  if (!status || !transitionKind) return null;
2985
3732
  return {
2986
3733
  canPurchase: readBoolean(record.can_purchase ?? record.canPurchase, true),
2987
3734
  status: status === "current_recurring_plan" || status === "owned_additive_unlock" ? status : "available",
2988
3735
  transitionKind: transitionKind === "start_recurring" || transitionKind === "replace_recurring" || transitionKind === "buy_additive_unlock" || transitionKind === "buy_credit_pack" || transitionKind === "activate_hybrid" ? transitionKind : "none",
2989
- reason: readString3(record.reason) || null
3736
+ reason: readString4(record.reason) || null
2990
3737
  };
2991
3738
  }
2992
3739
  function resolveMonetizationPackagePurchasePolicy(input) {
@@ -2995,20 +3742,23 @@ function resolveMonetizationPackagePurchasePolicy(input) {
2995
3742
  if (projectedPolicy) return projectedPolicy;
2996
3743
  const currentSubscription = input.currentSubscription && typeof input.currentSubscription === "object" && !Array.isArray(input.currentSubscription) ? input.currentSubscription : {};
2997
3744
  const additiveEntitlements = Array.isArray(input.additiveEntitlements) ? input.additiveEntitlements : [];
2998
- const productFamily = readLower(item.productFamily);
2999
- const packageKind = readLower(item.packageKind);
3000
- const productId = readLower(item.productId);
3001
- const currentSubscriptionProductId = readLower(currentSubscription.product_id);
3745
+ const productFamily = readLower2(item.productFamily);
3746
+ const packageKind = readLower2(item.packageKind);
3747
+ const productId = readLower2(item.productId);
3748
+ const currentSubscriptionProductId = readLower2(currentSubscription.product_id);
3002
3749
  const includedCredits = readPackageCredits(item);
3003
3750
  const ownershipCandidates = new Set(collectPackageOwnershipCandidates(item));
3751
+ const currentSubscriptionCandidates = new Set(
3752
+ collectCurrentSubscriptionCandidates(currentSubscription)
3753
+ );
3004
3754
  const ownedAdditiveUnlock = additiveEntitlements.some((entry) => {
3005
3755
  const entitlement = entry && typeof entry === "object" && !Array.isArray(entry) ? entry : {};
3006
3756
  if (!hasCurrentOwnedEntitlement(entitlement)) return false;
3007
- const entitlementProductId = readLower(entitlement.product_id);
3757
+ const entitlementProductId = readLower2(entitlement.product_id);
3008
3758
  if (productId && entitlementProductId && productId === entitlementProductId) return true;
3009
3759
  const candidateValues = [
3010
- readLower(entitlement.product_slug),
3011
- readLower(entitlement.tier)
3760
+ readLower2(entitlement.product_slug),
3761
+ readLower2(entitlement.tier)
3012
3762
  ].filter(Boolean);
3013
3763
  return candidateValues.some((value) => ownershipCandidates.has(value));
3014
3764
  });
@@ -3020,6 +3770,14 @@ function resolveMonetizationPackagePurchasePolicy(input) {
3020
3770
  reason: "current_recurring_plan"
3021
3771
  };
3022
3772
  }
3773
+ if (hasActiveRecurringSubscription(currentSubscription) && Array.from(ownershipCandidates).some((value) => currentSubscriptionCandidates.has(value))) {
3774
+ return {
3775
+ canPurchase: false,
3776
+ status: "current_recurring_plan",
3777
+ transitionKind: "none",
3778
+ reason: "current_recurring_plan"
3779
+ };
3780
+ }
3023
3781
  const consumableOneTimeUnlock = (productFamily === "one_time_unlock" || packageKind === "one_time_unlock") && includedCredits > 0;
3024
3782
  if (consumableOneTimeUnlock) {
3025
3783
  return {
@@ -3077,17 +3835,19 @@ function resolveMonetizationPackagePurchasePolicy(input) {
3077
3835
  };
3078
3836
  }
3079
3837
  function normalizeMoneyLabel(item) {
3080
- const amount = readString3(item.amount);
3081
- const currency = readString3(item.currency);
3082
- const billingPeriod = readString3(item.billingPeriod);
3083
- if (!amount && !currency) return "Price unavailable";
3838
+ const amount = readString4(item.amount);
3839
+ const currency = readString4(item.currency);
3840
+ const billingPeriod = readString4(item.billingPeriod);
3841
+ if (!amount && !currency) {
3842
+ return buildXmsSurfaceCopy({ locale: item.locale }).priceUnavailableLabel;
3843
+ }
3084
3844
  return `${amount} ${currency}${billingPeriod ? ` / ${billingPeriod}` : ""}`.trim();
3085
3845
  }
3086
3846
  function summarizeXappMonetizationSnapshot(input) {
3087
3847
  const record = input && typeof input === "object" && !Array.isArray(input) ? input : {};
3088
3848
  const accessProjection = record.access_projection && typeof record.access_projection === "object" && !Array.isArray(record.access_projection) ? record.access_projection : null;
3089
3849
  const currentSubscription = record.current_subscription && typeof record.current_subscription === "object" && !Array.isArray(record.current_subscription) ? record.current_subscription : null;
3090
- const overduePolicy = currentSubscription?.overdue_policy && typeof currentSubscription.overdue_policy === "object" && !Array.isArray(currentSubscription.overdue_policy) ? currentSubscription.overdue_policy : null;
3850
+ const lifecycle = buildXmsSubscriptionLifecycleSummary({ currentSubscription });
3091
3851
  return {
3092
3852
  accessCoverage: {
3093
3853
  available: hasEffectiveCoverage({ accessProjection, currentSubscription }),
@@ -3097,19 +3857,22 @@ function summarizeXappMonetizationSnapshot(input) {
3097
3857
  sourceRefLabel: formatStateLabel(accessProjection?.source_ref)
3098
3858
  },
3099
3859
  currentSubscription: {
3100
- present: Boolean(currentSubscription),
3101
- statusLabel: formatStateLabel(currentSubscription?.status),
3860
+ present: lifecycle.present,
3861
+ statusLabel: lifecycle.statusLabel || formatStateLabel(currentSubscription?.status),
3102
3862
  tierLabel: formatStateLabel(currentSubscription?.tier),
3103
- coverageLabel: overduePolicy?.has_current_access ? "Still active" : "Expired or blocked",
3104
- coverageReasonLabel: overduePolicy?.effective_status_reason ? formatStateLabel(overduePolicy.effective_status_reason) : "No active overdue restriction.",
3105
- renewsAt: readString3(currentSubscription?.renews_at) || null,
3106
- expiresAt: readString3(currentSubscription?.current_period_ends_at) || null,
3863
+ coverageLabel: lifecycle.coverageLabel || buildXmsSurfaceCopy().unknownLabel,
3864
+ coverageReasonLabel: lifecycle.reasonLabel || buildXmsSurfaceCopy().noOverdueRestrictionLabel,
3865
+ renewsAt: lifecycle.renewsAt,
3866
+ expiresAt: lifecycle.expiresAt || lifecycle.currentPeriodEndsAt,
3107
3867
  paymentSessionIdLabel: formatStateLabel(currentSubscription?.payment_session_id)
3108
3868
  },
3109
3869
  wallet: {
3110
- creditsRemaining: readString3(accessProjection?.credits_remaining) || "0",
3870
+ creditsRemaining: readString4(accessProjection?.credits_remaining) || "0",
3871
+ virtualCurrencyLabel: formatVirtualCurrencyLabel(accessProjection?.virtual_currency, {
3872
+ includeCode: true
3873
+ }),
3111
3874
  balanceStateLabel: formatStateLabel(accessProjection?.balance_state, "unknown"),
3112
- currentAccessLabel: hasEffectiveCoverage({ accessProjection, currentSubscription }) ? "Yes" : "No"
3875
+ currentAccessLabel: hasEffectiveCoverage({ accessProjection, currentSubscription }) ? buildXmsSurfaceCopy().yesLabel : buildXmsSurfaceCopy().noLabel
3113
3876
  }
3114
3877
  };
3115
3878
  }
@@ -3118,6 +3881,19 @@ function summarizeXappMonetizationSnapshot(input) {
3118
3881
  import { useCallback, useEffect as useEffect5, useMemo as useMemo4, useRef, useState as useState3 } from "react";
3119
3882
  import { Link as Link5, useLocation as useLocation3 } from "react-router-dom";
3120
3883
  import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
3884
+ function formatVirtualCurrencyLabel2(input, options) {
3885
+ const record = asRecord(input);
3886
+ const code = readString(record.code);
3887
+ const name = readString(record.name);
3888
+ if (name && code && options?.includeCode) return `${name} (${code})`;
3889
+ return name || code || "";
3890
+ }
3891
+ function formatVirtualCurrencyAmount(value, virtualCurrency) {
3892
+ const amount = readString(value);
3893
+ if (!amount) return "";
3894
+ const currencyLabel = formatVirtualCurrencyLabel2(virtualCurrency);
3895
+ return currencyLabel ? `${amount} ${currencyLabel}` : amount;
3896
+ }
3121
3897
  function useQueryToken3() {
3122
3898
  const loc = useLocation3();
3123
3899
  const qs = new URLSearchParams(loc.search);
@@ -3171,13 +3947,22 @@ function MonetizationPage() {
3171
3947
  const [xappTitle, setXappTitle] = useState3("");
3172
3948
  const visibilityRefreshRef = useRef(0);
3173
3949
  const isEmbedded = typeof window !== "undefined" && window.location.pathname.startsWith("/embed");
3950
+ const overview = useMemo4(
3951
+ () => ({
3952
+ apps: items.length,
3953
+ subscriptions: items.filter((item) => item.hasSubscription).length,
3954
+ namedCurrencies: items.filter((item) => item.hasNamedCurrency).length,
3955
+ balances: items.filter((item) => item.hasBalance).length
3956
+ }),
3957
+ [items]
3958
+ );
3174
3959
  const refresh = useCallback(async () => {
3175
3960
  if (!client.getMyXappMonetization) {
3176
3961
  setError(
3177
3962
  t(
3178
3963
  "activity.unavailable_monetization_title",
3179
3964
  void 0,
3180
- "Monetization is unavailable in this host."
3965
+ "Plans and balances are unavailable in this host."
3181
3966
  )
3182
3967
  );
3183
3968
  setItems([]);
@@ -3225,21 +4010,41 @@ function MonetizationPage() {
3225
4010
  try {
3226
4011
  const next = await Promise.all(
3227
4012
  deduped.map(async (item) => {
3228
- const detail = await client.getCatalogXapp(item.xappId, {
3229
- installationId: item.installationId || null
3230
- });
4013
+ const [detail, state, history] = await Promise.all([
4014
+ client.getCatalogXapp(item.xappId, {
4015
+ installationId: item.installationId || null
4016
+ }),
4017
+ client.getMyXappMonetization(item.xappId, {
4018
+ installationId: item.installationId || null,
4019
+ locale
4020
+ }),
4021
+ typeof client.getMyXappMonetizationHistory === "function" ? client.getMyXappMonetizationHistory(item.xappId, {
4022
+ installationId: item.installationId || null,
4023
+ limit: 20
4024
+ }) : Promise.resolve(null)
4025
+ ]);
3231
4026
  if (!xappIdFilter && !isMonetizationCandidate(detail)) return null;
3232
- const state = await client.getMyXappMonetization(item.xappId, {
3233
- installationId: item.installationId || null,
3234
- locale
3235
- });
3236
4027
  const summary = summarizeXappMonetizationSnapshot(state);
4028
+ const balanceSummary = summarizeVirtualCurrencyBalances(history).balances.map(
4029
+ (entry) => entry.amountLabel
4030
+ );
3237
4031
  const detailRecord = asRecord(detail);
4032
+ const accessProjection = asRecord(asRecord(state).access_projection);
4033
+ const virtualCurrencyLabel = formatVirtualCurrencyLabel2(
4034
+ accessProjection.virtual_currency,
4035
+ {
4036
+ includeCode: true
4037
+ }
4038
+ );
4039
+ const creditsRemainingLabel = formatVirtualCurrencyAmount(
4040
+ accessProjection.credits_remaining,
4041
+ accessProjection.virtual_currency
4042
+ ) || summary.wallet.creditsRemaining || "0";
3238
4043
  const title = resolveMarketplaceText(asRecord(detailRecord.manifest).title, locale) || readFirstString(asRecord(detailRecord.xapp).name) || item.xappId;
3239
4044
  const subtitle = resolveMarketplaceText(asRecord(detailRecord.manifest).summary, locale) || resolveMarketplaceText(asRecord(detailRecord.manifest).description, locale) || t(
3240
4045
  "activity.monetization_card_subtitle",
3241
4046
  void 0,
3242
- "Current XMS state, active access, subscriptions, and credits for this app."
4047
+ "Access, plans, and balances for this app."
3243
4048
  );
3244
4049
  return {
3245
4050
  xappId: item.xappId,
@@ -3275,8 +4080,13 @@ function MonetizationPage() {
3275
4080
  "No recurring coverage"
3276
4081
  ),
3277
4082
  renewsAt: summary.currentSubscription.renewsAt || t("activity.monetization_not_scheduled", void 0, "Not scheduled"),
3278
- creditsRemaining: summary.wallet.creditsRemaining || "0",
3279
- balanceState: summary.wallet.balanceStateLabel || t("activity.monetization_balance_unknown", void 0, "unknown")
4083
+ virtualCurrencyLabel,
4084
+ creditsRemaining: creditsRemainingLabel,
4085
+ balanceState: summary.wallet.balanceStateLabel || t("activity.monetization_balance_unknown", void 0, "unknown"),
4086
+ balanceSummary,
4087
+ hasSubscription: summary.currentSubscription.present,
4088
+ hasNamedCurrency: Boolean(virtualCurrencyLabel),
4089
+ hasBalance: Boolean(balanceSummary.length || creditsRemainingLabel)
3280
4090
  };
3281
4091
  })
3282
4092
  );
@@ -3374,7 +4184,7 @@ function MonetizationPage() {
3374
4184
  return suffix ? `?${suffix}` : "";
3375
4185
  })()
3376
4186
  } : null;
3377
- return /* @__PURE__ */ jsxs5("div", { className: `mx-catalog-container ${isEmbedded ? "is-embedded" : ""}`, children: [
4187
+ return /* @__PURE__ */ jsxs5("div", { className: `mx-catalog-container mx-monetization-page ${isEmbedded ? "is-embedded" : ""}`, children: [
3378
4188
  /* @__PURE__ */ jsxs5("div", { className: "mx-breadcrumb", children: [
3379
4189
  /* @__PURE__ */ jsx9(Link5, { to: isEmbedded ? "/" : "/marketplace", children: t("common.marketplace", void 0, "Marketplace") }),
3380
4190
  xappLink && /* @__PURE__ */ jsxs5(Fragment4, { children: [
@@ -3443,95 +4253,170 @@ function MonetizationPage() {
3443
4253
  "."
3444
4254
  ] })
3445
4255
  ] }) : error ? /* @__PURE__ */ jsx9("div", { className: "mx-table-container mx-alert mx-alert-error", children: error }) : null,
3446
- xappIdFilter ? /* @__PURE__ */ jsxs5("div", { className: "mx-subtle-note", children: [
3447
- t("activity.showing_monetization_for_prefix", void 0, "Showing XMS state for"),
4256
+ xappIdFilter ? /* @__PURE__ */ jsx9("div", { className: "mx-table-container mx-subtle-note-card", children: /* @__PURE__ */ jsxs5("div", { className: "mx-subtle-note mx-subtle-note-compact", children: [
4257
+ t(
4258
+ "activity.showing_monetization_for_prefix",
4259
+ void 0,
4260
+ "Showing plans and balances for"
4261
+ ),
3448
4262
  " ",
3449
4263
  /* @__PURE__ */ jsx9("span", { className: "mx-subtle-note-strong", children: xappIdFilter })
3450
- ] }) : /* @__PURE__ */ jsx9("div", { className: "mx-subtle-note", children: showPast ? t(
4264
+ ] }) }) : /* @__PURE__ */ jsx9("div", { className: "mx-table-container mx-subtle-note-card", children: /* @__PURE__ */ jsx9("div", { className: "mx-subtle-note mx-subtle-note-compact", children: showPast ? t(
3451
4265
  "activity.monetization_overview_hint_with_past",
3452
4266
  void 0,
3453
- "Review current and past XMS access, subscriptions, and credits across this subject's apps."
4267
+ "Review current and past plans, subscriptions, and balances across this subject's apps."
3454
4268
  ) : t(
3455
4269
  "activity.monetization_overview_hint",
3456
4270
  void 0,
3457
- "Review current XMS access, subscriptions, and credits across the apps linked to this subject."
3458
- ) }),
3459
- busy ? /* @__PURE__ */ jsx9("div", { className: "mx-table-container", children: t("activity.loading_monetization", void 0, "Loading monetization state...") }) : null,
3460
- !busy && !error && items.length === 0 ? /* @__PURE__ */ jsx9("div", { className: "mx-table-container", children: showPast ? t(
3461
- "activity.no_monetization_history",
3462
- void 0,
3463
- "No monetization history was found for this subject."
3464
- ) : t(
3465
- "activity.no_monetization_current",
4271
+ "Review current plans, subscriptions, and balances across this subject's apps."
4272
+ ) }) }),
4273
+ /* @__PURE__ */ jsx9("section", { className: "mx-table-container mx-monetization-summary-card", children: /* @__PURE__ */ jsxs5("div", { className: "mx-monetization-card-body", children: [
4274
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-panel-head", children: /* @__PURE__ */ jsxs5("div", { children: [
4275
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-panel-kicker", children: t("activity.monetization_title", void 0, "Monetization") }),
4276
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-panel-id", children: t("activity.monetization_summary_title", void 0, "Plans and balances") }),
4277
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-panel-subtitle", children: t(
4278
+ "activity.monetization_summary_subtitle",
4279
+ void 0,
4280
+ "Review active plans, subscriptions, and balances before opening app details or history."
4281
+ ) })
4282
+ ] }) }),
4283
+ /* @__PURE__ */ jsxs5("div", { className: "mx-record-grid", children: [
4284
+ /* @__PURE__ */ jsxs5("div", { className: "mx-record-field", children: [
4285
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-label", children: t("activity.monetization_summary_apps", void 0, "Apps") }),
4286
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-value is-strong", children: overview.apps })
4287
+ ] }),
4288
+ /* @__PURE__ */ jsxs5("div", { className: "mx-record-field", children: [
4289
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-label", children: t("activity.monetization_summary_subscriptions", void 0, "Subscriptions") }),
4290
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-value is-strong", children: overview.subscriptions })
4291
+ ] }),
4292
+ /* @__PURE__ */ jsxs5("div", { className: "mx-record-field", children: [
4293
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-label", children: t("activity.monetization_summary_balances", void 0, "Balances") }),
4294
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-value is-strong", children: overview.balances })
4295
+ ] }),
4296
+ /* @__PURE__ */ jsxs5("div", { className: "mx-record-field", children: [
4297
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-label", children: t("activity.monetization_summary_currencies", void 0, "Named currencies") }),
4298
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-value is-strong", children: overview.namedCurrencies })
4299
+ ] })
4300
+ ] })
4301
+ ] }) }),
4302
+ busy ? /* @__PURE__ */ jsx9("div", { className: "mx-table-container", children: /* @__PURE__ */ jsx9("div", { className: "mx-loading-center mx-loading-table", children: t(
4303
+ "activity.loading_monetization",
3466
4304
  void 0,
3467
- "No current monetization coverage was found for this subject."
3468
- ) }) : null,
3469
- !busy && items.length > 0 ? /* @__PURE__ */ jsx9("div", { className: "mx-record-panel-stack", children: items.map((item) => /* @__PURE__ */ jsxs5("section", { className: "mx-record-panel mx-record-panel-monetization", children: [
4305
+ "Loading plans, balances, and recent activity..."
4306
+ ) }) }) : null,
4307
+ !busy && !error && items.length === 0 ? /* @__PURE__ */ jsx9("div", { className: "mx-table-container", children: /* @__PURE__ */ jsxs5("div", { className: "mx-empty-catalog", children: [
4308
+ /* @__PURE__ */ jsx9("div", { className: "mx-empty-catalog-icon", children: "\u25CE" }),
4309
+ /* @__PURE__ */ jsx9("div", { className: "mx-empty-catalog-title", children: showPast ? t(
4310
+ "activity.no_monetization_history",
4311
+ void 0,
4312
+ "No plan or balance history was found for this subject."
4313
+ ) : t(
4314
+ "activity.no_monetization_current",
4315
+ void 0,
4316
+ "No current plans or balances were found for this subject."
4317
+ ) }),
4318
+ /* @__PURE__ */ jsx9("div", { className: "mx-empty-catalog-desc", children: showPast ? t(
4319
+ "activity.monetization_overview_hint_with_past",
4320
+ void 0,
4321
+ "Review current and past plans, subscriptions, and balances across this subject's apps."
4322
+ ) : t(
4323
+ "activity.monetization_overview_hint",
4324
+ void 0,
4325
+ "Review current plans, subscriptions, and balances across this subject's apps."
4326
+ ) })
4327
+ ] }) }) : null,
4328
+ !busy && items.length > 0 ? /* @__PURE__ */ jsx9("div", { className: "mx-record-panel-stack", children: items.map((item) => /* @__PURE__ */ jsx9("section", { className: "mx-table-container mx-monetization-activity-card", children: /* @__PURE__ */ jsxs5("div", { className: "mx-monetization-card-body", children: [
3470
4329
  /* @__PURE__ */ jsxs5("div", { className: "mx-record-panel-head", children: [
3471
4330
  /* @__PURE__ */ jsxs5("div", { children: [
3472
4331
  /* @__PURE__ */ jsx9("div", { className: "mx-record-panel-kicker", children: t("activity.monetization", void 0, "Monetization") }),
3473
4332
  /* @__PURE__ */ jsx9("div", { className: "mx-record-panel-id", children: item.title }),
3474
- /* @__PURE__ */ jsx9("div", { className: "mx-subtle-note mx-subtle-note-compact", children: item.subtitle })
4333
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-panel-subtitle", children: item.subtitle }),
4334
+ /* @__PURE__ */ jsxs5("div", { className: "mx-monetization-card-badges", children: [
4335
+ /* @__PURE__ */ jsx9("span", { className: "mx-badge mx-badge-warning", children: item.accessLabel }),
4336
+ /* @__PURE__ */ jsx9(
4337
+ "span",
4338
+ {
4339
+ className: `mx-badge ${item.hasSubscription ? "mx-badge-success" : "mx-badge-warning"}`,
4340
+ children: item.subscriptionStatus
4341
+ }
4342
+ ),
4343
+ /* @__PURE__ */ jsx9("span", { className: "mx-tag", children: item.virtualCurrencyLabel || t("activity.monetization_no_currency", void 0, "No named currency") })
4344
+ ] })
3475
4345
  ] }),
3476
- /* @__PURE__ */ jsxs5("div", { className: "mx-record-actions", children: [
3477
- !xappIdFilter ? /* @__PURE__ */ jsx9(
3478
- Link5,
3479
- {
3480
- to: {
3481
- pathname: isEmbedded ? "/monetization" : "/marketplace/monetization",
3482
- search: (() => {
3483
- const qs = new URLSearchParams();
3484
- if (token) qs.set("token", token);
3485
- qs.set("xappId", item.xappId);
3486
- if (item.installationId) qs.set("installationId", item.installationId);
3487
- const suffix = qs.toString();
3488
- return suffix ? `?${suffix}` : "";
3489
- })()
3490
- },
3491
- className: "mx-btn mx-btn-ghost",
3492
- children: t("activity.monetization_focus_xapp", void 0, "Focus this app")
3493
- }
3494
- ) : null,
3495
- /* @__PURE__ */ jsx9(Link5, { to: item.plansHref, className: "mx-btn mx-btn-primary", children: t("activity.monetization_open_plans", void 0, "Open plans") }),
3496
- /* @__PURE__ */ jsx9(Link5, { to: item.historyHref, className: "mx-btn mx-btn-secondary", children: t("activity.monetization_open_history", void 0, "Open history") }),
3497
- /* @__PURE__ */ jsx9(Link5, { to: item.detailHref, className: "mx-btn mx-btn-ghost", children: t("common.view_app_details", void 0, "View app details") })
4346
+ /* @__PURE__ */ jsxs5("div", { className: "mx-record-actions mx-record-actions-monetization", children: [
4347
+ /* @__PURE__ */ jsxs5("div", { className: "mx-action-group", children: [
4348
+ /* @__PURE__ */ jsx9(Link5, { to: item.plansHref, className: "mx-btn mx-btn-primary", children: t("activity.monetization_open_plans", void 0, "View plans") }),
4349
+ /* @__PURE__ */ jsx9(Link5, { to: item.historyHref, className: "mx-btn mx-btn-secondary", children: t("activity.monetization_open_history", void 0, "View history") })
4350
+ ] }),
4351
+ /* @__PURE__ */ jsxs5("div", { className: "mx-action-group", children: [
4352
+ /* @__PURE__ */ jsx9(Link5, { to: item.detailHref, className: "mx-btn mx-btn-ghost", children: t("common.view_app_details", void 0, "View app details") }),
4353
+ !xappIdFilter ? /* @__PURE__ */ jsx9(
4354
+ Link5,
4355
+ {
4356
+ to: {
4357
+ pathname: isEmbedded ? "/monetization" : "/marketplace/monetization",
4358
+ search: (() => {
4359
+ const qs = new URLSearchParams();
4360
+ if (token) qs.set("token", token);
4361
+ qs.set("xappId", item.xappId);
4362
+ if (item.installationId)
4363
+ qs.set("installationId", item.installationId);
4364
+ const suffix = qs.toString();
4365
+ return suffix ? `?${suffix}` : "";
4366
+ })()
4367
+ },
4368
+ className: "mx-btn mx-btn-ghost",
4369
+ children: t("activity.monetization_focus_xapp", void 0, "Only this app")
4370
+ }
4371
+ ) : null
4372
+ ] })
3498
4373
  ] })
3499
4374
  ] }),
3500
- /* @__PURE__ */ jsxs5("div", { className: "mx-record-grid", children: [
4375
+ /* @__PURE__ */ jsxs5("div", { className: "mx-record-grid mx-monetization-card-primary-grid", children: [
3501
4376
  /* @__PURE__ */ jsxs5("div", { className: "mx-record-field", children: [
3502
- /* @__PURE__ */ jsx9("div", { className: "mx-record-label", children: t("activity.monetization_access_label", void 0, "Current access") }),
4377
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-label", children: t("activity.monetization_access_label", void 0, "Access") }),
3503
4378
  /* @__PURE__ */ jsx9("div", { className: "mx-record-value is-strong", children: item.accessLabel })
3504
4379
  ] }),
3505
4380
  /* @__PURE__ */ jsxs5("div", { className: "mx-record-field", children: [
3506
- /* @__PURE__ */ jsx9("div", { className: "mx-record-label", children: t("activity.monetization_plan_label", void 0, "Current plan") }),
4381
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-label", children: t("activity.monetization_plan_label", void 0, "Plan") }),
3507
4382
  /* @__PURE__ */ jsx9("div", { className: "mx-record-value is-strong", children: item.tierLabel })
3508
4383
  ] }),
3509
- /* @__PURE__ */ jsxs5("div", { className: "mx-record-field", children: [
3510
- /* @__PURE__ */ jsx9("div", { className: "mx-record-label", children: t("activity.monetization_credits_label", void 0, "Credits remaining") }),
3511
- /* @__PURE__ */ jsx9("div", { className: "mx-record-value is-strong", children: item.creditsRemaining })
3512
- ] }),
3513
4384
  /* @__PURE__ */ jsxs5("div", { className: "mx-record-field", children: [
3514
4385
  /* @__PURE__ */ jsx9("div", { className: "mx-record-label", children: t("activity.monetization_subscription_label", void 0, "Subscription") }),
3515
4386
  /* @__PURE__ */ jsx9("div", { className: "mx-record-value", children: item.subscriptionStatus })
3516
4387
  ] }),
3517
4388
  /* @__PURE__ */ jsxs5("div", { className: "mx-record-field", children: [
3518
- /* @__PURE__ */ jsx9("div", { className: "mx-record-label", children: t("activity.monetization_coverage_label", void 0, "Coverage") }),
3519
- /* @__PURE__ */ jsx9("div", { className: "mx-record-value", children: item.subscriptionCoverage })
4389
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-label", children: t("activity.monetization_credits_label", void 0, "Balance") }),
4390
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-value is-strong", children: item.creditsRemaining })
3520
4391
  ] }),
3521
4392
  /* @__PURE__ */ jsxs5("div", { className: "mx-record-field", children: [
3522
4393
  /* @__PURE__ */ jsx9("div", { className: "mx-record-label", children: t("activity.monetization_renews_at", void 0, "Renews at") }),
3523
4394
  /* @__PURE__ */ jsx9("div", { className: "mx-record-value", children: item.renewsAt })
4395
+ ] })
4396
+ ] }),
4397
+ /* @__PURE__ */ jsxs5("div", { className: "mx-monetization-card-secondary", children: [
4398
+ /* @__PURE__ */ jsxs5("div", { className: "mx-monetization-card-secondary-row", children: [
4399
+ /* @__PURE__ */ jsx9("span", { className: "mx-monetization-card-secondary-label", children: t("xapp.virtual_currency_label", void 0, "Currency") }),
4400
+ /* @__PURE__ */ jsx9("span", { className: "mx-monetization-card-secondary-value", children: item.virtualCurrencyLabel || "\u2014" })
3524
4401
  ] }),
3525
- /* @__PURE__ */ jsxs5("div", { className: "mx-record-field", children: [
3526
- /* @__PURE__ */ jsx9("div", { className: "mx-record-label", children: t("activity.monetization_balance_state", void 0, "Balance state") }),
3527
- /* @__PURE__ */ jsx9("div", { className: "mx-record-value", children: item.balanceState })
4402
+ /* @__PURE__ */ jsxs5("div", { className: "mx-monetization-card-secondary-row", children: [
4403
+ /* @__PURE__ */ jsx9("span", { className: "mx-monetization-card-secondary-label", children: t("activity.monetization_coverage_label", void 0, "Renewal state") }),
4404
+ /* @__PURE__ */ jsx9("span", { className: "mx-monetization-card-secondary-value", children: item.subscriptionCoverage })
3528
4405
  ] }),
3529
- /* @__PURE__ */ jsxs5("div", { className: "mx-record-field", children: [
3530
- /* @__PURE__ */ jsx9("div", { className: "mx-record-label", children: t("activity.monetization_source_label", void 0, "Source") }),
3531
- /* @__PURE__ */ jsx9("div", { className: "mx-record-value", children: item.sourceLabel })
4406
+ /* @__PURE__ */ jsxs5("div", { className: "mx-monetization-card-secondary-row", children: [
4407
+ /* @__PURE__ */ jsx9("span", { className: "mx-monetization-card-secondary-label", children: t("activity.monetization_balance_state", void 0, "Balance status") }),
4408
+ /* @__PURE__ */ jsx9("span", { className: "mx-monetization-card-secondary-value", children: item.balanceState })
4409
+ ] }),
4410
+ /* @__PURE__ */ jsxs5("div", { className: "mx-monetization-card-secondary-row", children: [
4411
+ /* @__PURE__ */ jsx9("span", { className: "mx-monetization-card-secondary-label", children: t("activity.monetization_source_label", void 0, "Origin") }),
4412
+ /* @__PURE__ */ jsx9("span", { className: "mx-monetization-card-secondary-value", children: item.sourceLabel })
3532
4413
  ] })
3533
- ] })
3534
- ] }, item.xappId)) }) : null
4414
+ ] }),
4415
+ item.balanceSummary.length > 0 ? /* @__PURE__ */ jsxs5("div", { className: "mx-monetization-card-balance-strip", children: [
4416
+ /* @__PURE__ */ jsx9("div", { className: "mx-record-label", children: t("activity.monetization_balances_label", void 0, "Balances") }),
4417
+ /* @__PURE__ */ jsx9("div", { className: "mx-tag-list", children: item.balanceSummary.map((entry) => /* @__PURE__ */ jsx9("span", { className: "mx-tag", children: entry }, `${item.xappId}:${entry}`)) })
4418
+ ] }) : null
4419
+ ] }) }, item.xappId)) }) : null
3535
4420
  ] });
3536
4421
  }
3537
4422
 
@@ -4386,7 +5271,7 @@ function SchemaOutputView({ schema, value }) {
4386
5271
  function asRecord3(value) {
4387
5272
  return value && typeof value === "object" ? value : {};
4388
5273
  }
4389
- function readString4(value) {
5274
+ function readString5(value) {
4390
5275
  return typeof value === "string" ? value.trim() : "";
4391
5276
  }
4392
5277
  function resolveAction(summary) {
@@ -4401,13 +5286,13 @@ function resolveAction(summary) {
4401
5286
  return {};
4402
5287
  }
4403
5288
  function normalizeActionKind(raw) {
4404
- return readString4(raw).toLowerCase();
5289
+ return readString5(raw).toLowerCase();
4405
5290
  }
4406
5291
  function resolveText(t, key, fallback) {
4407
5292
  return typeof t === "function" ? t(key, fallback) : fallback;
4408
5293
  }
4409
5294
  function isSettledPaymentStatus(value) {
4410
- const normalized = readString4(value).toLowerCase();
5295
+ const normalized = readString5(value).toLowerCase();
4411
5296
  return normalized === "paid" || normalized === "settled" || normalized === "succeeded" || normalized === "completed";
4412
5297
  }
4413
5298
  function resolveCtaLabel(actionKind, t) {
@@ -4448,7 +5333,7 @@ function resolveLockMessage(reason, paymentAttemptState, reconcileState, t) {
4448
5333
  "Payment is not settled. Complete a new payment attempt."
4449
5334
  );
4450
5335
  }
4451
- const attempt = readString4(paymentAttemptState).toLowerCase();
5336
+ const attempt = readString5(paymentAttemptState).toLowerCase();
4452
5337
  if (attempt === "requires_action") {
4453
5338
  return resolveText(
4454
5339
  t,
@@ -4494,13 +5379,13 @@ function resolvePaymentLockStateFromGuardSummary(summaryInput, options) {
4494
5379
  const summary = asRecord3(summaryInput);
4495
5380
  const action = resolveAction(summary);
4496
5381
  const actionKind = normalizeActionKind(String(action.kind ?? summary.reason ?? ""));
4497
- const actionUrl = readString4(action.url);
4498
- const reason = readString4(summary.reason).toLowerCase();
5382
+ const actionUrl = readString5(action.url);
5383
+ const reason = readString5(summary.reason).toLowerCase();
4499
5384
  const monetizationState = asRecord3(summary.monetization_state);
4500
- const paymentSessionId = readString4(monetizationState.payment_session_id) || readString4(action.payment_session_id);
4501
- const paymentAttemptState = readString4(monetizationState.payment_attempt_state).toLowerCase();
5385
+ const paymentSessionId = readString5(monetizationState.payment_session_id) || readString5(action.payment_session_id);
5386
+ const paymentAttemptState = readString5(monetizationState.payment_attempt_state).toLowerCase();
4502
5387
  const reconcileState = (() => {
4503
- const candidate = readString4(options?.reconcileState).toLowerCase();
5388
+ const candidate = readString5(options?.reconcileState).toLowerCase();
4504
5389
  if (candidate === "confirming_payment" || candidate === "still_pending" || candidate === "confirmed_paid" || candidate === "failed") {
4505
5390
  return candidate;
4506
5391
  }
@@ -4508,7 +5393,7 @@ function resolvePaymentLockStateFromGuardSummary(summaryInput, options) {
4508
5393
  })();
4509
5394
  const isPaymentKind = actionKind === "complete_payment" || actionKind === "payment_required";
4510
5395
  const isPaymentReason = reason === "payment_required" || reason === "payment_evidence_missing" || reason === "payment_receipt_already_used";
4511
- const requestStatus = readString4(options?.requestStatus).toUpperCase();
5396
+ const requestStatus = readString5(options?.requestStatus).toUpperCase();
4512
5397
  const paymentSettled = isSettledPaymentStatus(options?.paymentStatus);
4513
5398
  const isHeldForPayment = requestStatus === "PAYMENT_PENDING";
4514
5399
  const isResolvedPastHold = paymentSettled && requestStatus !== "" && !isHeldForPayment;
@@ -5992,7 +6877,7 @@ function asRecord6(value) {
5992
6877
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
5993
6878
  return value;
5994
6879
  }
5995
- function readString5(value) {
6880
+ function readString6(value) {
5996
6881
  return typeof value === "string" ? value.trim() : "";
5997
6882
  }
5998
6883
  function readBoolean2(value, fallback) {
@@ -6067,7 +6952,7 @@ function stripMonetizationCheckoutReturnParams(search) {
6067
6952
  return rendered ? `?${rendered}` : "";
6068
6953
  }
6069
6954
  function formatDateTime2(value, locale) {
6070
- const raw = readString5(value);
6955
+ const raw = readString6(value);
6071
6956
  if (!raw) return "";
6072
6957
  const parsed = new Date(raw);
6073
6958
  if (Number.isNaN(parsed.getTime())) return raw;
@@ -6083,6 +6968,30 @@ function formatDateTime2(value, locale) {
6083
6968
  return parsed.toISOString();
6084
6969
  }
6085
6970
  }
6971
+ function readVirtualCurrencyDefinition2(value) {
6972
+ const record = asRecord6(value);
6973
+ if (!record) return null;
6974
+ const code = readString6(record.code);
6975
+ const name = readString6(record.name);
6976
+ if (!code && !name) return null;
6977
+ return record;
6978
+ }
6979
+ function formatVirtualCurrencyLabel3(value, options) {
6980
+ const record = readVirtualCurrencyDefinition2(value);
6981
+ if (!record) return "";
6982
+ const code = readString6(record.code);
6983
+ const name = readString6(record.name);
6984
+ if (options?.includeCode && name && code && name.toLowerCase() !== code.toLowerCase()) {
6985
+ return `${name} (${code})`;
6986
+ }
6987
+ return name || code;
6988
+ }
6989
+ function formatVirtualCurrencyAmount2(value, virtualCurrency) {
6990
+ const amount = readString6(value);
6991
+ if (!amount) return "";
6992
+ const currencyLabel = formatVirtualCurrencyLabel3(virtualCurrency);
6993
+ return currencyLabel ? `${amount} ${currencyLabel}` : amount;
6994
+ }
6086
6995
  function normalizeUsageCreditSummary(value) {
6087
6996
  const summary = asRecord6(value);
6088
6997
  if (!summary) return null;
@@ -6097,7 +7006,7 @@ function normalizeUsageCreditSummary(value) {
6097
7006
  const byTool = byToolRaw.map((entry) => {
6098
7007
  const record = asRecord6(entry);
6099
7008
  if (!record) return null;
6100
- const toolName = readString5(record.tool_name);
7009
+ const toolName = readString6(record.tool_name);
6101
7010
  if (!toolName) return null;
6102
7011
  return {
6103
7012
  tool_name: toolName,
@@ -6123,14 +7032,14 @@ function normalizeUsageCreditSummary(value) {
6123
7032
  reserved_active_count: reservedActiveCount,
6124
7033
  reserved_stale_count: reservedStaleCount,
6125
7034
  consumed_count: consumedCount,
6126
- updated_at: readString5(summary.updated_at) || null,
7035
+ updated_at: readString6(summary.updated_at) || null,
6127
7036
  by_tool: byTool
6128
7037
  };
6129
7038
  }
6130
7039
  function normalizeGuardPolicyKind(policy) {
6131
7040
  if (policy === "all" || policy === "any") return policy;
6132
7041
  const policyObj = asRecord6(policy);
6133
- const mode = readString5(policyObj?.mode);
7042
+ const mode = readString6(policyObj?.mode);
6134
7043
  return mode === "any" ? "any" : "all";
6135
7044
  }
6136
7045
  function defaultBlockingForTrigger(trigger) {
@@ -6149,12 +7058,12 @@ function buildMonetizationHookSummaryItems(manifest) {
6149
7058
  return [];
6150
7059
  }
6151
7060
  const baseItems = [];
6152
- const defaultInvoiceRef = readString5(
7061
+ const defaultInvoiceRef = readString6(
6153
7062
  afterPaymentCompleted.invoice_ref ?? afterPaymentCompleted.invoiceRef
6154
7063
  );
6155
7064
  baseItems.push({
6156
7065
  slug: "xms_after_payment_completed",
6157
- label: defaultInvoiceRef ? `XMS payment completed \xB7 ${defaultInvoiceRef}` : "XMS payment completed",
7066
+ label: defaultInvoiceRef ? `Payment completed \xB7 ${defaultInvoiceRef}` : "Payment completed",
6158
7067
  trigger: "after:payment_completed",
6159
7068
  headless: true,
6160
7069
  blocking: false,
@@ -6167,10 +7076,10 @@ function buildMonetizationHookSummaryItems(manifest) {
6167
7076
  for (const [paymentGuardRef, rawValue] of Object.entries(byPaymentGuardRef ?? {})) {
6168
7077
  const config = asRecord6(rawValue);
6169
7078
  if (!config || readBoolean2(config.enabled, true) === false) continue;
6170
- const invoiceRef = readString5(config.invoice_ref ?? config.invoiceRef);
7079
+ const invoiceRef = readString6(config.invoice_ref ?? config.invoiceRef);
6171
7080
  baseItems.push({
6172
7081
  slug: `xms_after_payment_completed_${paymentGuardRef}`,
6173
- label: invoiceRef ? `XMS payment completed \xB7 ${paymentGuardRef} \xB7 ${invoiceRef}` : `XMS payment completed \xB7 ${paymentGuardRef}`,
7082
+ label: invoiceRef ? `Payment completed \xB7 ${paymentGuardRef} \xB7 ${invoiceRef}` : `Payment completed \xB7 ${paymentGuardRef}`,
6174
7083
  trigger: "after:payment_completed",
6175
7084
  headless: true,
6176
7085
  blocking: false,
@@ -6258,9 +7167,17 @@ function XappDetailPageContent(props) {
6258
7167
  const [checkoutBusyPackageSlug, setCheckoutBusyPackageSlug] = useState8("");
6259
7168
  const [checkoutError, setCheckoutError] = useState8(null);
6260
7169
  const [checkoutNotice, setCheckoutNotice] = useState8(null);
7170
+ const [subscriptionActionBusy, setSubscriptionActionBusy] = useState8(
7171
+ ""
7172
+ );
7173
+ const [subscriptionActionError, setSubscriptionActionError] = useState8(null);
7174
+ const [cancelSubscriptionConfirmOpen, setCancelSubscriptionConfirmOpen] = useState8(false);
6261
7175
  const checkoutFinalizeKeyRef = useRef2("");
6262
7176
  const installationsByXappId = hasSubject ? host.getInstallationsByXappId() : {};
6263
7177
  const routeInstallationId = String(routeQuery.get("installationId") || "").trim();
7178
+ const routePreviewAt = String(
7179
+ routeQuery.get("previewAt") || routeQuery.get("preview_at") || ""
7180
+ ).trim();
6264
7181
  const installation = xappId && installationsByXappId[String(xappId)] ? installationsByXappId[String(xappId)] : xappId && routeInstallationId ? {
6265
7182
  installationId: routeInstallationId,
6266
7183
  xappId: String(xappId)
@@ -6271,6 +7188,7 @@ function XappDetailPageContent(props) {
6271
7188
  const widgetsEnabled = Boolean(hasSubject) && (Boolean(installation) || autoAvailableMode) && (!updateAvailable || autoUpdateMode);
6272
7189
  const isEmbedded = window.location.pathname.startsWith("/embed");
6273
7190
  const singleXappMode = env?.singleXappMode;
7191
+ const lifecyclePreviewEnabled = env?.devMode === true;
6274
7192
  const routeSurfaceView = routeView === "history" ? "history" : "plans";
6275
7193
  const refresh = useCallback2(async () => {
6276
7194
  if (!xappId) return;
@@ -6282,7 +7200,7 @@ function XappDetailPageContent(props) {
6282
7200
  });
6283
7201
  setData(asRecord6(res));
6284
7202
  } catch (e) {
6285
- setError(readString5(asRecord6(e)?.message) || String(e));
7203
+ setError(readString6(asRecord6(e)?.message) || String(e));
6286
7204
  } finally {
6287
7205
  setBusy(false);
6288
7206
  }
@@ -6296,13 +7214,22 @@ function XappDetailPageContent(props) {
6296
7214
  try {
6297
7215
  const next = await client.getMyXappMonetization(currentXappId, {
6298
7216
  installationId: installation?.installationId ?? null,
6299
- locale
7217
+ locale,
7218
+ previewAt: lifecyclePreviewEnabled ? routePreviewAt || null : null
6300
7219
  });
6301
7220
  setMonetization(next);
6302
7221
  } catch {
6303
7222
  setMonetization(null);
6304
7223
  }
6305
- }, [client, host.subjectId, installation?.installationId, locale, xappId]);
7224
+ }, [
7225
+ client,
7226
+ host.subjectId,
7227
+ installation?.installationId,
7228
+ lifecyclePreviewEnabled,
7229
+ locale,
7230
+ routePreviewAt,
7231
+ xappId
7232
+ ]);
6306
7233
  const refreshMonetizationHistory = useCallback2(async () => {
6307
7234
  const currentXappId = String(xappId ?? "").trim();
6308
7235
  if (!currentXappId || !host.subjectId || typeof client.getMyXappMonetizationHistory !== "function") {
@@ -6373,18 +7300,18 @@ function XappDetailPageContent(props) {
6373
7300
  const xappRecord = asRecord6(data?.xapp);
6374
7301
  const versionRecord = asRecord6(data?.version);
6375
7302
  const publisherRecord = asRecord6(xappRecord?.publisher);
6376
- const title = resolveMarketplaceText(manifest?.title, locale) || readString5(xappRecord?.name) || t("xapp.kicker_default", void 0, "Xapp");
6377
- const description = resolveMarketplaceText(manifest?.description, locale) || readString5(xappRecord?.description) || "";
6378
- const imageUrl = readString5(manifest?.image) || "https://picsum.photos/seed/xapps-detail/840/360";
7303
+ const title = resolveMarketplaceText(manifest?.title, locale) || readString6(xappRecord?.name) || t("xapp.kicker_default", void 0, "Xapp");
7304
+ const description = resolveMarketplaceText(manifest?.description, locale) || readString6(xappRecord?.description) || "";
7305
+ const imageUrl = readString6(manifest?.image) || "https://picsum.photos/seed/xapps-detail/840/360";
6379
7306
  const widgets = Array.isArray(data?.widgets) ? data.widgets.filter((widget) => Boolean(asRecord6(widget))) : [];
6380
7307
  const defaultWidget = useMemo9(() => {
6381
7308
  const def = widgets.find((w) => readBoolean2(w.default, false));
6382
7309
  return def || widgets[0] || null;
6383
7310
  }, [widgets]);
6384
7311
  const requestedWidget = useMemo9(() => {
6385
- const desiredToolName = readString5(queryToolName);
7312
+ const desiredToolName = readString6(queryToolName);
6386
7313
  if (!desiredToolName) return defaultWidget;
6387
- return widgets.find((widget) => readString5(widget.bind_tool_name) === desiredToolName) || defaultWidget;
7314
+ return widgets.find((widget) => readString6(widget.bind_tool_name) === desiredToolName) || defaultWidget;
6388
7315
  }, [defaultWidget, queryToolName, widgets]);
6389
7316
  const backTo = {
6390
7317
  pathname: isEmbedded ? "/embed/catalog" : "..",
@@ -6406,8 +7333,8 @@ function XappDetailPageContent(props) {
6406
7333
  };
6407
7334
  const terms = asRecord6(manifest?.terms);
6408
7335
  const termsTitle = resolveMarketplaceText(terms?.title, locale) || t("xapp.terms_title", void 0, "Terms & Conditions");
6409
- const termsText = resolveMarketplaceText(terms?.text, locale) || readString5(terms?.text);
6410
- const termsUrl = readString5(terms?.url);
7336
+ const termsText = resolveMarketplaceText(terms?.text, locale) || readString6(terms?.text);
7337
+ const termsUrl = readString6(terms?.url);
6411
7338
  const hasTermsContent = Boolean(termsText || termsUrl);
6412
7339
  const requiresTerms = Boolean(terms || action === "install" || action === "update");
6413
7340
  function requestInstallForWidget(widgetId, widgetName = null, acceptedTerms = false, openAfterInstall = false) {
@@ -6423,13 +7350,13 @@ function XappDetailPageContent(props) {
6423
7350
  }
6424
7351
  function requestUpdateForWidget(widgetId, acceptedTerms = false) {
6425
7352
  if (!installation?.installationId || !host.requestUpdate) return;
6426
- const activeWidget = widgetId && Array.isArray(widgets) ? widgets.find((entry) => readString5(entry.id) === widgetId) || null : null;
7353
+ const activeWidget = widgetId && Array.isArray(widgets) ? widgets.find((entry) => readString6(entry.id) === widgetId) || null : null;
6427
7354
  host.requestUpdate({
6428
7355
  installationId: installation.installationId,
6429
7356
  xappId: String(xappId ?? ""),
6430
7357
  widgetId,
6431
7358
  xappTitle: String(title),
6432
- widgetName: resolveMarketplaceText(activeWidget?.title, locale) || readString5(activeWidget?.name) || null,
7359
+ widgetName: resolveMarketplaceText(activeWidget?.title, locale) || readString6(activeWidget?.name) || null,
6433
7360
  ...acceptedTerms ? { termsAccepted: true } : {}
6434
7361
  });
6435
7362
  }
@@ -6485,7 +7412,7 @@ function XappDetailPageContent(props) {
6485
7412
  if (action === "install") {
6486
7413
  setTermsAccepted(false);
6487
7414
  setTermsAction("install");
6488
- setTermsWidgetId(readString5(defaultWidget?.id) || null);
7415
+ setTermsWidgetId(readString6(defaultWidget?.id) || null);
6489
7416
  setTermsWidgetName(resolveMarketplaceText(defaultWidget?.title, locale) || null);
6490
7417
  setTermsOpen(true);
6491
7418
  return;
@@ -6503,20 +7430,20 @@ function XappDetailPageContent(props) {
6503
7430
  if (env?.embedMode) return;
6504
7431
  if (!requestedWidget || !widgetsEnabled) return;
6505
7432
  const widget = requestedWidget;
6506
- const widgetId = readString5(widget?.id);
7433
+ const widgetId = readString6(widget?.id);
6507
7434
  if (!widgetId) return;
6508
7435
  const key = [
6509
7436
  String(xappId ?? ""),
6510
7437
  installation?.installationId || "auto",
6511
7438
  widgetId,
6512
- readString5(queryToolName)
7439
+ readString6(queryToolName)
6513
7440
  ].join(":");
6514
7441
  if (autoOpenedWidgetKeyRef.current === key) return;
6515
7442
  autoOpenedWidgetKeyRef.current = key;
6516
7443
  launchWidgetForSubject(
6517
7444
  widgetId,
6518
- resolveMarketplaceText(widget?.title, locale) || readString5(widget?.widget_name) || readString5(widget?.name) || t("common.widget", void 0, "Widget"),
6519
- readString5(widget?.bind_tool_name)
7445
+ resolveMarketplaceText(widget?.title, locale) || readString6(widget?.widget_name) || readString6(widget?.name) || t("common.widget", void 0, "Widget"),
7446
+ readString6(widget?.bind_tool_name)
6520
7447
  );
6521
7448
  }, [
6522
7449
  action,
@@ -6562,8 +7489,8 @@ function XappDetailPageContent(props) {
6562
7489
  }
6563
7490
  return t("activity.requests_title", void 0, "Requests");
6564
7491
  }
6565
- const publisherSlug = readString5(publisherRecord?.slug);
6566
- const publisherName = readString5(publisherRecord?.name) || publisherSlug;
7492
+ const publisherSlug = readString6(publisherRecord?.slug);
7493
+ const publisherName = readString6(publisherRecord?.name) || publisherSlug;
6567
7494
  const publisherTo = publisherSlug ? {
6568
7495
  pathname: isEmbedded ? `/publishers/${encodeURIComponent(publisherSlug)}` : `/marketplace/publishers/${encodeURIComponent(publisherSlug)}`,
6569
7496
  search: tokenSearch
@@ -6574,8 +7501,8 @@ function XappDetailPageContent(props) {
6574
7501
  const guardItems = guardsRaw.map((raw) => {
6575
7502
  const guard = asRecord6(raw);
6576
7503
  if (!guard) return null;
6577
- const trigger = readString5(guard.trigger);
6578
- const slug = readString5(guard.slug);
7504
+ const trigger = readString6(guard.trigger);
7505
+ const slug = readString6(guard.slug);
6579
7506
  if (!trigger || !slug) return null;
6580
7507
  const policyKind = normalizeGuardPolicyKind(policyMap[trigger]);
6581
7508
  return {
@@ -6615,7 +7542,7 @@ function XappDetailPageContent(props) {
6615
7542
  );
6616
7543
  const selectedPaywall = useMemo9(
6617
7544
  () => monetizationPaywalls.find(
6618
- (item) => readString5(asRecord6(item)?.slug).trim().toLowerCase() === requestedPaywallSlug
7545
+ (item) => readString6(asRecord6(item)?.slug).trim().toLowerCase() === requestedPaywallSlug
6619
7546
  ) || selectXappMonetizationPaywall({
6620
7547
  paywalls: monetizationPaywalls,
6621
7548
  placement: "default_paywall"
@@ -6693,7 +7620,8 @@ function XappDetailPageContent(props) {
6693
7620
  if (typeof client.getMyXappMonetization === "function") {
6694
7621
  const next = await client.getMyXappMonetization(currentXappId, {
6695
7622
  installationId: installation?.installationId ?? null,
6696
- locale
7623
+ locale,
7624
+ previewAt: lifecyclePreviewEnabled ? routePreviewAt || null : null
6697
7625
  });
6698
7626
  if (!cancelled) setMonetization(next);
6699
7627
  }
@@ -6705,7 +7633,7 @@ function XappDetailPageContent(props) {
6705
7633
  }
6706
7634
  } catch (error2) {
6707
7635
  if (cancelled) return;
6708
- const message = readString5(asRecord6(error2)?.message) || (error2 instanceof Error ? error2.message : "") || t(
7636
+ const message = readString6(asRecord6(error2)?.message) || (error2 instanceof Error ? error2.message : "") || t(
6709
7637
  "xapp.checkout_finalize_failed",
6710
7638
  void 0,
6711
7639
  "Payment returned, but access refresh did not complete yet."
@@ -6727,9 +7655,56 @@ function XappDetailPageContent(props) {
6727
7655
  paymentReturnIntentId,
6728
7656
  paymentReturnSessionId,
6729
7657
  paymentReturnStatus,
7658
+ lifecyclePreviewEnabled,
7659
+ routePreviewAt,
6730
7660
  t,
6731
7661
  xappId
6732
7662
  ]);
7663
+ async function refreshSubscriptionLifecycle() {
7664
+ const currentXappId = String(xappId ?? "").trim();
7665
+ const contractId = readString6(monetizationSubscription?.id);
7666
+ if (!currentXappId || !contractId || typeof client.refreshMyXappSubscriptionContractState !== "function") {
7667
+ return;
7668
+ }
7669
+ setSubscriptionActionBusy("refresh");
7670
+ setSubscriptionActionError(null);
7671
+ try {
7672
+ await client.refreshMyXappSubscriptionContractState({
7673
+ xappId: currentXappId,
7674
+ contractId
7675
+ });
7676
+ await refreshMonetization();
7677
+ await refreshMonetizationHistory();
7678
+ } catch (error2) {
7679
+ const message = readString6(asRecord6(error2)?.message) || (error2 instanceof Error ? error2.message : "") || t("xapp.subscription_refresh_failed", void 0, "Unable to refresh subscription state.");
7680
+ setSubscriptionActionError(message);
7681
+ } finally {
7682
+ setSubscriptionActionBusy("");
7683
+ }
7684
+ }
7685
+ async function cancelSubscriptionLifecycle() {
7686
+ const currentXappId = String(xappId ?? "").trim();
7687
+ const contractId = readString6(monetizationSubscription?.id);
7688
+ if (!currentXappId || !contractId || typeof client.cancelMyXappSubscriptionContract !== "function") {
7689
+ return;
7690
+ }
7691
+ setSubscriptionActionBusy("cancel");
7692
+ setSubscriptionActionError(null);
7693
+ try {
7694
+ await client.cancelMyXappSubscriptionContract({
7695
+ xappId: currentXappId,
7696
+ contractId
7697
+ });
7698
+ await refreshMonetization();
7699
+ await refreshMonetizationHistory();
7700
+ setCancelSubscriptionConfirmOpen(false);
7701
+ } catch (error2) {
7702
+ const message = readString6(asRecord6(error2)?.message) || (error2 instanceof Error ? error2.message : "") || t("xapp.subscription_cancel_failed", void 0, "Unable to cancel this subscription.");
7703
+ setSubscriptionActionError(message);
7704
+ } finally {
7705
+ setSubscriptionActionBusy("");
7706
+ }
7707
+ }
6733
7708
  async function finalizeCurrentUserCheckoutIntent(currentXappId, intentId) {
6734
7709
  if (typeof client.finalizeMyXappPurchasePaymentSession !== "function") {
6735
7710
  throw new Error(
@@ -6751,7 +7726,8 @@ function XappDetailPageContent(props) {
6751
7726
  if (typeof client.getMyXappMonetization === "function") {
6752
7727
  const next = await client.getMyXappMonetization(currentXappId, {
6753
7728
  installationId: installation?.installationId ?? null,
6754
- locale
7729
+ locale,
7730
+ previewAt: lifecyclePreviewEnabled ? routePreviewAt || null : null
6755
7731
  });
6756
7732
  setMonetization(next);
6757
7733
  }
@@ -6775,7 +7751,7 @@ function XappDetailPageContent(props) {
6775
7751
  return;
6776
7752
  }
6777
7753
  const pkg = selectedPaywallPackageRecords.find(
6778
- (item) => readString5(item.packageSlug).trim().toLowerCase() === normalizedSlug
7754
+ (item) => readString6(item.packageSlug).trim().toLowerCase() === normalizedSlug
6779
7755
  );
6780
7756
  if (pkg) {
6781
7757
  const purchasePolicy = getPackagePurchasePolicy(pkg);
@@ -6794,9 +7770,9 @@ function XappDetailPageContent(props) {
6794
7770
  return;
6795
7771
  }
6796
7772
  }
6797
- const offeringId = readString5(pkg?.offeringId);
6798
- const packageId = readString5(pkg?.packageId);
6799
- const priceId = readString5(pkg?.priceId);
7773
+ const offeringId = readString6(pkg?.offeringId);
7774
+ const packageId = readString6(pkg?.packageId);
7775
+ const priceId = readString6(pkg?.priceId);
6800
7776
  if (!offeringId || !packageId || !priceId) {
6801
7777
  setCheckoutError(
6802
7778
  t(
@@ -6836,10 +7812,10 @@ function XappDetailPageContent(props) {
6836
7812
  locale
6837
7813
  });
6838
7814
  const paymentPageUrl = normalizeHostedCheckoutUrl({
6839
- paymentPageUrl: readString5(payment.payment_page_url),
7815
+ paymentPageUrl: readString6(payment.payment_page_url),
6840
7816
  apiBaseUrl: env?.apiBaseUrl || null
6841
7817
  });
6842
- const paymentStatus = readString5(payment.payment_session?.status).trim().toLowerCase();
7818
+ const paymentStatus = readString6(payment.payment_session?.status).trim().toLowerCase();
6843
7819
  if (!paymentPageUrl && (paymentStatus === "paid" || paymentStatus === "completed")) {
6844
7820
  await finalizeCurrentUserCheckoutIntent(
6845
7821
  String(xappId),
@@ -6858,7 +7834,7 @@ function XappDetailPageContent(props) {
6858
7834
  }
6859
7835
  navigateToHostedCheckout(paymentPageUrl);
6860
7836
  } catch (error2) {
6861
- 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.");
7837
+ const message = readString6(asRecord6(error2)?.message) || (error2 instanceof Error ? error2.message : "") || t("xapp.checkout_start_failed", void 0, "Unable to start checkout for this package.");
6862
7838
  setCheckoutError(message);
6863
7839
  } finally {
6864
7840
  setCheckoutBusyPackageSlug("");
@@ -6869,44 +7845,71 @@ function XappDetailPageContent(props) {
6869
7845
  const monetizationSubscription = asRecord6(monetization?.current_subscription);
6870
7846
  const additiveEntitlements = Array.isArray(monetization?.additive_entitlements) ? monetization.additive_entitlements.map((item) => asRecord6(item)).filter((item) => item ? Object.keys(item).length > 0 : false) : [];
6871
7847
  const activeAdditiveEntitlements = additiveEntitlements.filter((item) => {
6872
- const status = readString5(item.status).trim().toLowerCase();
7848
+ const status = readString6(item.status).trim().toLowerCase();
6873
7849
  return status === "active" || status === "grace_period";
6874
7850
  });
6875
- const additiveUnlockLabels = activeAdditiveEntitlements.map((item) => readString5(item.tier) || readString5(item.product_slug)).filter(Boolean);
6876
- const overduePolicy = asRecord6(monetizationSubscription?.overdue_policy);
6877
- const currentTier = readString5(monetizationSubscription?.tier) || readString5(monetizationAccess?.tier);
6878
- const balanceState = readString5(monetizationAccess?.balance_state);
6879
- const subscriptionStatus = readString5(monetizationSubscription?.status);
6880
- 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;
6881
- const subscriptionReasonKey = readString5(overduePolicy?.effective_status_reason);
6882
- const subscriptionReason = subscriptionReasonKey === "grace_covered_past_due" ? t(
6883
- "xapp.subscription_reason_grace_covered_past_due",
6884
- void 0,
6885
- "Coverage remains during grace period"
6886
- ) : subscriptionReasonKey === "past_due_after_period_end" ? t(
6887
- "xapp.subscription_reason_past_due_after_period_end",
6888
- void 0,
6889
- "Current period ended without successful renewal"
6890
- ) : subscriptionReasonKey === "expired_after_boundary" ? t(
6891
- "xapp.subscription_reason_expired_after_boundary",
6892
- void 0,
6893
- "Expiry boundary reached"
6894
- ) : null;
6895
- const overdueSince = formatDateTime2(overduePolicy?.overdue_since, locale);
6896
- const expiryBoundaryAt = formatDateTime2(overduePolicy?.expiry_boundary_at, locale);
6897
- const renewsAt = formatDateTime2(monetizationSubscription?.renews_at, locale);
6898
- const expiresAt = formatDateTime2(monetizationSubscription?.expired_at, locale) || formatDateTime2(monetizationSubscription?.current_period_ends_at, locale);
6899
- const creditsRemaining = readString5(monetizationAccess?.credits_remaining);
7851
+ const additiveUnlockLabels = activeAdditiveEntitlements.map((item) => readString6(item.tier) || readString6(item.product_slug)).filter(Boolean).reduce((labels, label) => {
7852
+ if (!labels.includes(label)) labels.push(label);
7853
+ return labels;
7854
+ }, []);
7855
+ const subscriptionLifecycle = buildXmsSubscriptionLifecycleSummary({
7856
+ currentSubscription: monetizationSubscription,
7857
+ locale
7858
+ });
7859
+ const subscriptionManagement = asRecord6(monetizationSubscription?.subscription_management);
7860
+ const subscriptionSubjectActions = asRecord6(subscriptionManagement?.subject_actions);
7861
+ const canRefreshSubscriptionAction = readBoolean2(
7862
+ asRecord6(subscriptionSubjectActions?.refresh_status)?.available,
7863
+ true
7864
+ );
7865
+ const canCancelSubscriptionAction = readBoolean2(
7866
+ asRecord6(subscriptionSubjectActions?.cancel_subscription)?.available,
7867
+ true
7868
+ );
7869
+ const currentTier = readString6(monetizationSubscription?.tier) || readString6(monetizationAccess?.tier);
7870
+ const balanceState = readString6(monetizationAccess?.balance_state);
7871
+ const subscriptionStatus = subscriptionLifecycle.statusLabel;
7872
+ const subscriptionCoverage = subscriptionLifecycle.coverageLabel;
7873
+ const subscriptionReason = subscriptionLifecycle.reasonLabel;
7874
+ const overdueSince = formatDateTime2(subscriptionLifecycle.overdueSince, locale);
7875
+ const expiryBoundaryAt = formatDateTime2(subscriptionLifecycle.expiryBoundaryAt, locale);
7876
+ const renewsAt = formatDateTime2(subscriptionLifecycle.renewsAt, locale);
7877
+ const currentPeriodEndsAt = formatDateTime2(subscriptionLifecycle.currentPeriodEndsAt, locale);
7878
+ const cancelledAt = formatDateTime2(subscriptionLifecycle.cancelledAt, locale);
7879
+ const expiresAt = formatDateTime2(subscriptionLifecycle.expiresAt, locale);
7880
+ const lifecyclePreviewAt = lifecyclePreviewEnabled ? formatDateTime2(routePreviewAt, locale) : "";
7881
+ const creditsRemaining = readString6(monetizationAccess?.credits_remaining);
7882
+ const accessVirtualCurrencyLabel = formatVirtualCurrencyLabel3(
7883
+ monetizationAccess?.virtual_currency,
7884
+ {
7885
+ includeCode: true
7886
+ }
7887
+ );
7888
+ const creditsRemainingLabel = formatVirtualCurrencyAmount2(
7889
+ monetizationAccess?.credits_remaining,
7890
+ monetizationAccess?.virtual_currency
7891
+ );
7892
+ const currentBalanceSummary = useMemo9(() => {
7893
+ const historySource = asRecord6(monetizationHistory)?.history ?? monetizationHistory;
7894
+ const summarized = summarizeVirtualCurrencyBalances({
7895
+ history: historySource
7896
+ }).balances;
7897
+ if (summarized.length > 0) {
7898
+ return summarized.map((item) => item.amountLabel).filter(Boolean);
7899
+ }
7900
+ if (creditsRemainingLabel) return [creditsRemainingLabel];
7901
+ return [];
7902
+ }, [creditsRemainingLabel, monetizationHistory]);
6900
7903
  const accessState = resolveMarketplaceDefaultAccessState({
6901
7904
  projection: monetizationAccessProjection,
6902
7905
  hasCatalogMonetization,
6903
7906
  availableLabel: t("xapp.access_state_available", void 0, "available")
6904
7907
  });
6905
7908
  const hasMonetizationState = Boolean(
6906
- currentTier || accessState || subscriptionStatus || subscriptionCoverage || subscriptionReason || overdueSince || expiryBoundaryAt || renewsAt || expiresAt || creditsRemaining || additiveUnlockLabels.length > 0
7909
+ currentTier || accessState || subscriptionStatus || subscriptionCoverage || subscriptionReason || overdueSince || expiryBoundaryAt || renewsAt || currentPeriodEndsAt || cancelledAt || expiresAt || lifecyclePreviewAt || accessVirtualCurrencyLabel || currentBalanceSummary.length > 0 || creditsRemaining || additiveUnlockLabels.length > 0
6907
7910
  );
6908
- const manifestScreenshots = Array.isArray(manifest?.screenshots) ? manifest.screenshots.map((shot) => readString5(shot)).filter(Boolean) : [];
6909
- const manifestTags = Array.isArray(manifest?.tags) ? manifest.tags.map((tag) => readString5(tag)).filter(Boolean) : [];
7911
+ const manifestScreenshots = Array.isArray(manifest?.screenshots) ? manifest.screenshots.map((shot) => readString6(shot)).filter(Boolean) : [];
7912
+ const manifestTags = Array.isArray(manifest?.tags) ? manifest.tags.map((tag) => readString6(tag)).filter(Boolean) : [];
6910
7913
  function getPackagePurchasePolicy(item) {
6911
7914
  return resolveMonetizationPackagePurchasePolicy({
6912
7915
  item,
@@ -6916,7 +7919,7 @@ function XappDetailPageContent(props) {
6916
7919
  });
6917
7920
  }
6918
7921
  const currentAccessCard = hasMonetizationState ? /* @__PURE__ */ jsxs11("div", { className: "mx-sidebar-card", children: [
6919
- /* @__PURE__ */ jsx15("h3", { className: "mx-section-title mx-detail-sidebar-title", children: t("xapp.current_access_title", void 0, "Current Access") }),
7922
+ /* @__PURE__ */ jsx15("h3", { className: "mx-section-title mx-detail-sidebar-title", children: t("xapp.current_access_title", void 0, "Current access") }),
6920
7923
  currentTier ? /* @__PURE__ */ jsxs11("div", { className: "mx-meta-item", children: [
6921
7924
  /* @__PURE__ */ jsx15("span", { className: "mx-meta-label", children: t("xapp.current_plan_label", void 0, "Current plan") }),
6922
7925
  /* @__PURE__ */ jsx15("span", { className: "mx-meta-value", children: currentTier })
@@ -6926,7 +7929,7 @@ function XappDetailPageContent(props) {
6926
7929
  /* @__PURE__ */ jsx15("span", { className: "mx-meta-value", children: accessState })
6927
7930
  ] }) : null,
6928
7931
  subscriptionStatus ? /* @__PURE__ */ jsxs11("div", { className: "mx-meta-item", children: [
6929
- /* @__PURE__ */ jsx15("span", { className: "mx-meta-label", children: t("xapp.subscription_status_label", void 0, "Subscription status") }),
7932
+ /* @__PURE__ */ jsx15("span", { className: "mx-meta-label", children: t("xapp.subscription_status_label", void 0, "Subscription state") }),
6930
7933
  /* @__PURE__ */ jsx15("span", { className: "mx-meta-value", children: subscriptionStatus })
6931
7934
  ] }) : null,
6932
7935
  subscriptionCoverage ? /* @__PURE__ */ jsxs11("div", { className: "mx-meta-item", children: [
@@ -6949,75 +7952,147 @@ function XappDetailPageContent(props) {
6949
7952
  /* @__PURE__ */ jsx15("span", { className: "mx-meta-label", children: t("xapp.renews_at_label", void 0, "Renews at") }),
6950
7953
  /* @__PURE__ */ jsx15("span", { className: "mx-meta-value", children: renewsAt })
6951
7954
  ] }) : null,
7955
+ currentPeriodEndsAt ? /* @__PURE__ */ jsxs11("div", { className: "mx-meta-item", children: [
7956
+ /* @__PURE__ */ jsx15("span", { className: "mx-meta-label", children: t("xapp.current_period_ends_label", void 0, "Current period ends") }),
7957
+ /* @__PURE__ */ jsx15("span", { className: "mx-meta-value", children: currentPeriodEndsAt })
7958
+ ] }) : null,
7959
+ cancelledAt ? /* @__PURE__ */ jsxs11("div", { className: "mx-meta-item", children: [
7960
+ /* @__PURE__ */ jsx15("span", { className: "mx-meta-label", children: t("xapp.cancelled_at_label", void 0, "Cancelled at") }),
7961
+ /* @__PURE__ */ jsx15("span", { className: "mx-meta-value", children: cancelledAt })
7962
+ ] }) : null,
6952
7963
  expiresAt ? /* @__PURE__ */ jsxs11("div", { className: "mx-meta-item", children: [
6953
7964
  /* @__PURE__ */ jsx15("span", { className: "mx-meta-label", children: t("xapp.expires_at_label", void 0, "Expires at") }),
6954
7965
  /* @__PURE__ */ jsx15("span", { className: "mx-meta-value", children: expiresAt })
6955
7966
  ] }) : null,
7967
+ lifecyclePreviewAt ? /* @__PURE__ */ jsxs11("div", { className: "mx-meta-item", children: [
7968
+ /* @__PURE__ */ jsx15("span", { className: "mx-meta-label", children: t("xapp.lifecycle_preview_at_label", void 0, "Preview as of") }),
7969
+ /* @__PURE__ */ jsx15("span", { className: "mx-meta-value", children: lifecyclePreviewAt })
7970
+ ] }) : null,
7971
+ accessVirtualCurrencyLabel ? /* @__PURE__ */ jsxs11("div", { className: "mx-meta-item", children: [
7972
+ /* @__PURE__ */ jsx15("span", { className: "mx-meta-label", children: t("xapp.virtual_currency_label", void 0, "Currency") }),
7973
+ /* @__PURE__ */ jsx15("span", { className: "mx-meta-value", children: accessVirtualCurrencyLabel })
7974
+ ] }) : null,
7975
+ currentBalanceSummary.length > 0 ? /* @__PURE__ */ jsxs11("div", { className: "mx-meta-item mx-meta-item-top", children: [
7976
+ /* @__PURE__ */ jsx15("span", { className: "mx-meta-label", children: t("xapp.current_balances_label", void 0, "Balances now") }),
7977
+ /* @__PURE__ */ jsx15("div", { className: "mx-meta-value mx-meta-stack-sm", children: currentBalanceSummary.map((label, index) => /* @__PURE__ */ jsx15("div", { children: label }, `${label}:${index}`)) })
7978
+ ] }) : null,
6956
7979
  creditsRemaining ? /* @__PURE__ */ jsxs11("div", { className: "mx-meta-item", children: [
6957
- /* @__PURE__ */ jsx15("span", { className: "mx-meta-label", children: t("xapp.credits_remaining_label", void 0, "Credits remaining") }),
6958
- /* @__PURE__ */ jsx15("span", { className: "mx-meta-value", children: creditsRemaining })
7980
+ /* @__PURE__ */ jsx15("span", { className: "mx-meta-label", children: t("xapp.credits_remaining_label", void 0, "Balance") }),
7981
+ /* @__PURE__ */ jsx15("span", { className: "mx-meta-value", children: creditsRemainingLabel || creditsRemaining })
6959
7982
  ] }) : null,
6960
7983
  additiveUnlockLabels.length > 0 ? /* @__PURE__ */ jsxs11("div", { className: "mx-meta-item mx-meta-item-top", children: [
6961
7984
  /* @__PURE__ */ jsx15("span", { className: "mx-meta-label", children: t("xapp.add_on_unlocks_label", void 0, "Add-on unlocks") }),
6962
- /* @__PURE__ */ jsx15("div", { className: "mx-meta-value mx-meta-stack-sm", children: additiveUnlockLabels.map((label) => /* @__PURE__ */ jsx15("div", { children: label }, label)) })
7985
+ /* @__PURE__ */ jsx15("div", { className: "mx-meta-value mx-meta-stack-sm", children: additiveUnlockLabels.map((label, index) => /* @__PURE__ */ jsx15("div", { children: label }, `${label}:${index}`)) })
7986
+ ] }) : null,
7987
+ lifecyclePreviewAt ? /* @__PURE__ */ jsx15("div", { className: "mx-subtle-note", children: t(
7988
+ "xapp.lifecycle_preview_hint",
7989
+ void 0,
7990
+ "Subscription state is being previewed for the selected time."
7991
+ ) }) : null,
7992
+ subscriptionActionError ? /* @__PURE__ */ jsx15("div", { className: "mx-subtle-note", children: subscriptionActionError }) : null,
7993
+ monetizationSubscription?.id && (canRefreshSubscriptionAction && typeof client.refreshMyXappSubscriptionContractState === "function" || canCancelSubscriptionAction && subscriptionLifecycle.canCancel && typeof client.cancelMyXappSubscriptionContract === "function") ? /* @__PURE__ */ jsxs11("div", { className: "mx-detail-actions", children: [
7994
+ canRefreshSubscriptionAction && typeof client.refreshMyXappSubscriptionContractState === "function" ? /* @__PURE__ */ jsx15(
7995
+ "button",
7996
+ {
7997
+ className: "mx-btn mx-btn-secondary",
7998
+ disabled: subscriptionActionBusy !== "",
7999
+ onClick: () => {
8000
+ void refreshSubscriptionLifecycle();
8001
+ },
8002
+ children: subscriptionActionBusy === "refresh" ? t("xapp.subscription_refreshing", void 0, "Refreshing...") : t("xapp.subscription_refresh_action", void 0, "Refresh status")
8003
+ }
8004
+ ) : null,
8005
+ canCancelSubscriptionAction && subscriptionLifecycle.canCancel && typeof client.cancelMyXappSubscriptionContract === "function" ? /* @__PURE__ */ jsx15(
8006
+ "button",
8007
+ {
8008
+ className: "mx-btn mx-btn-outline",
8009
+ "data-variant": "danger",
8010
+ disabled: subscriptionActionBusy !== "",
8011
+ onClick: () => setCancelSubscriptionConfirmOpen(true),
8012
+ children: subscriptionActionBusy === "cancel" ? t("xapp.subscription_cancelling", void 0, "Cancelling...") : t("xapp.subscription_cancel_action", void 0, "Cancel subscription")
8013
+ }
8014
+ ) : null
6963
8015
  ] }) : null
6964
8016
  ] }) : null;
6965
8017
  const plansCard = selectedPaywallRenderModel ? /* @__PURE__ */ jsxs11("div", { className: "mx-sidebar-card", ref: plansSectionRef, children: [
6966
8018
  /* @__PURE__ */ jsx15("h3", { className: "mx-section-title mx-detail-sidebar-title", children: t("xapp.plan_options_title", void 0, "Plans") }),
6967
8019
  /* @__PURE__ */ jsxs11("div", { className: "mx-paywall-card-head", children: [
8020
+ /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-kicker", children: t("xapp.plan_options_title", void 0, "Plans") }),
6968
8021
  /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-title", children: selectedPaywallRenderModel.paywallLabel }),
6969
8022
  selectedPaywallRenderModel.summary ? /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-summary", children: selectedPaywallRenderModel.summary }) : null
6970
8023
  ] }),
6971
8024
  selectedPaywallRenderModel.badges.length > 0 ? /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-badges", children: selectedPaywallRenderModel.badges.map((badge) => /* @__PURE__ */ jsx15("span", { className: "mx-paywall-card-badge", children: badge }, badge)) }) : null,
6972
- /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-packages", children: selectedPaywallRenderModel.packages.map((item) => {
6973
- const normalizedPackageSlug = item.packageSlug.trim().toLowerCase();
6974
- const purchasePolicy = getPackagePurchasePolicy(item);
6975
- const packageSignals = item.signals.filter(
6976
- (signal) => !(purchasePolicy.transitionKind === "replace_recurring" && signal.toLowerCase().includes("trial"))
6977
- );
6978
- const isCurrentPackage = purchasePolicy.status === "current_recurring_plan";
6979
- const isOwnedAdditive = purchasePolicy.status === "owned_additive_unlock";
6980
- const isAdditiveCompanion = purchasePolicy.transitionKind === "buy_additive_unlock" && subscriptionStatus === "active";
6981
- return /* @__PURE__ */ jsxs11(
6982
- "div",
6983
- {
6984
- className: `mx-paywall-card-package ${item.isDefault ? "is-default" : ""} ${selectedPaywallPackageSlug && normalizedPackageSlug === selectedPaywallPackageSlug ? "is-selected" : ""}`,
6985
- children: [
6986
- /* @__PURE__ */ jsxs11("div", { className: "mx-paywall-card-package-head", children: [
6987
- /* @__PURE__ */ jsxs11("div", { children: [
6988
- /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-package-title", children: item.packageTitle }),
6989
- item.description ? /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-package-description", children: item.description }) : null
8025
+ /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-packages", children: selectedPaywallRenderModel.packages.map(
8026
+ (item, index) => {
8027
+ const normalizedPackageSlug = item.packageSlug.trim().toLowerCase();
8028
+ const purchasePolicy = getPackagePurchasePolicy(item);
8029
+ const packageSignals = item.signals.filter(
8030
+ (signal) => !(purchasePolicy.transitionKind === "replace_recurring" && signal.toLowerCase().includes("trial"))
8031
+ );
8032
+ const isCurrentPackage = purchasePolicy.status === "current_recurring_plan";
8033
+ const isOwnedAdditive = purchasePolicy.status === "owned_additive_unlock";
8034
+ const isAdditiveCompanion = purchasePolicy.transitionKind === "buy_additive_unlock" && subscriptionStatus === "active";
8035
+ const packageActionNote = isOwnedAdditive ? t(
8036
+ "xapp.owned_unlock_note",
8037
+ void 0,
8038
+ "This add-on is already included in the current access."
8039
+ ) : isCurrentPackage ? t(
8040
+ "xapp.current_plan_note",
8041
+ void 0,
8042
+ "This plan is already active for this app."
8043
+ ) : t(
8044
+ "xapp.checkout_hint",
8045
+ void 0,
8046
+ "Checkout opens in a secure hosted payment page managed by the platform."
8047
+ );
8048
+ return /* @__PURE__ */ jsxs11(
8049
+ "div",
8050
+ {
8051
+ className: `mx-paywall-card-package ${item.isDefault ? "is-default" : ""} ${selectedPaywallPackageSlug && normalizedPackageSlug === selectedPaywallPackageSlug ? "is-selected" : ""}`,
8052
+ children: [
8053
+ /* @__PURE__ */ jsxs11("div", { className: "mx-paywall-card-package-head", children: [
8054
+ /* @__PURE__ */ jsxs11("div", { children: [
8055
+ /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-package-title", children: item.packageTitle }),
8056
+ item.description ? /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-package-description", children: item.description }) : null
8057
+ ] }),
8058
+ /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-money", children: item.moneyLabel })
6990
8059
  ] }),
6991
- /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-money", children: item.moneyLabel })
6992
- ] }),
6993
- /* @__PURE__ */ jsxs11("div", { className: "mx-paywall-card-package-meta", children: [
6994
- /* @__PURE__ */ jsx15("span", { className: "mx-paywall-card-package-fit", children: item.fitLabel }),
6995
- selectedPaywallPackageSlug && normalizedPackageSlug === selectedPaywallPackageSlug ? /* @__PURE__ */ jsx15("span", { className: "mx-paywall-card-package-default", children: t("xapp.selected_label", void 0, "Selected") }) : null,
6996
- isOwnedAdditive ? /* @__PURE__ */ jsx15("span", { className: "mx-paywall-card-package-default", children: t("xapp.owned_unlock_label", void 0, "Owned unlock") }) : null,
6997
- isCurrentPackage && !isOwnedAdditive ? /* @__PURE__ */ jsx15("span", { className: "mx-paywall-card-package-default", children: t("xapp.current_plan_label", void 0, "Current plan") }) : null,
6998
- isAdditiveCompanion ? /* @__PURE__ */ jsx15("span", { className: "mx-paywall-card-package-default", children: t("xapp.additive_unlock_label", void 0, "Add-on with membership") }) : null,
6999
- item.isDefault ? /* @__PURE__ */ jsx15("span", { className: "mx-paywall-card-package-default", children: t("xapp.default_label", void 0, "Default") }) : null
7000
- ] }),
7001
- packageSignals.length > 0 ? /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-signals", children: packageSignals.map((signal) => /* @__PURE__ */ jsx15("span", { className: "mx-paywall-card-signal", children: signal }, signal)) }) : null,
7002
- isAdditiveCompanion ? /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-summary", children: t(
7003
- "xapp.additive_unlock_message",
7004
- void 0,
7005
- "This one-time unlock is additive. It adds access on top of the active recurring membership instead of replacing it."
7006
- ) }) : null,
7007
- typeof client.prepareMyXappPurchaseIntent === "function" && typeof client.createMyXappPurchasePaymentSession === "function" && hasSubject && canMutate ? /* @__PURE__ */ jsx15(
7008
- "button",
7009
- {
7010
- className: "mx-btn mx-btn-secondary",
7011
- disabled: !purchasePolicy.canPurchase || checkoutBusyPackageSlug === normalizedPackageSlug,
7012
- onClick: () => void startPackageCheckout(item.packageSlug),
7013
- 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")
7014
- }
7015
- ) : null
7016
- ]
7017
- },
7018
- item.packageId || item.packageSlug
7019
- );
7020
- }) }),
8060
+ /* @__PURE__ */ jsxs11("div", { className: "mx-paywall-card-package-meta", children: [
8061
+ /* @__PURE__ */ jsx15("span", { className: "mx-paywall-card-package-fit", children: item.fitLabel }),
8062
+ selectedPaywallPackageSlug && normalizedPackageSlug === selectedPaywallPackageSlug ? /* @__PURE__ */ jsx15("span", { className: "mx-paywall-card-package-default", children: t("xapp.selected_label", void 0, "Selected") }) : null,
8063
+ isOwnedAdditive ? /* @__PURE__ */ jsx15("span", { className: "mx-paywall-card-package-default", children: t("xapp.owned_unlock_label", void 0, "Owned unlock") }) : null,
8064
+ isCurrentPackage && !isOwnedAdditive ? /* @__PURE__ */ jsx15("span", { className: "mx-paywall-card-package-default", children: t("xapp.current_plan_label", void 0, "Current plan") }) : null,
8065
+ isAdditiveCompanion ? /* @__PURE__ */ jsx15("span", { className: "mx-paywall-card-package-default", children: t("xapp.additive_unlock_label", void 0, "Add-on with membership") }) : null,
8066
+ item.isDefault ? /* @__PURE__ */ jsx15("span", { className: "mx-paywall-card-package-default", children: t("xapp.default_label", void 0, "Default") }) : null
8067
+ ] }),
8068
+ packageSignals.length > 0 ? /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-signals", children: packageSignals.map((signal) => /* @__PURE__ */ jsx15("span", { className: "mx-paywall-card-signal", children: signal }, signal)) }) : null,
8069
+ isAdditiveCompanion ? /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-summary", children: t(
8070
+ "xapp.additive_unlock_message",
8071
+ void 0,
8072
+ "This one-time unlock is additive. It adds access on top of the active subscription instead of replacing it."
8073
+ ) }) : null,
8074
+ /* @__PURE__ */ jsxs11("div", { className: "mx-paywall-card-package-actions", children: [
8075
+ typeof client.prepareMyXappPurchaseIntent === "function" && typeof client.createMyXappPurchasePaymentSession === "function" && hasSubject && canMutate ? /* @__PURE__ */ jsx15(
8076
+ "button",
8077
+ {
8078
+ className: `mx-btn ${purchasePolicy.canPurchase && !checkoutBusyPackageSlug && !isOwnedAdditive && !isCurrentPackage ? "mx-btn-primary" : "mx-btn-secondary"}`,
8079
+ disabled: !purchasePolicy.canPurchase || checkoutBusyPackageSlug === normalizedPackageSlug,
8080
+ onClick: () => void startPackageCheckout(item.packageSlug),
8081
+ 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(
8082
+ "xapp.additive_unlock_action",
8083
+ void 0,
8084
+ "Purchase add-on unlock"
8085
+ ) : t("xapp.checkout_action", void 0, "Start checkout")
8086
+ }
8087
+ ) : null,
8088
+ /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-package-note", children: packageActionNote })
8089
+ ] })
8090
+ ]
8091
+ },
8092
+ `${item.packageId || item.packageSlug || normalizedPackageSlug}:${index}`
8093
+ );
8094
+ }
8095
+ ) }),
7021
8096
  checkoutNotice ? /* @__PURE__ */ jsx15("div", { className: "mx-paywall-card-summary", children: checkoutNotice }) : null,
7022
8097
  checkoutError ? /* @__PURE__ */ jsx15("div", { className: "mx-payment-lock-error", children: checkoutError }) : null
7023
8098
  ] }) : null;
@@ -7031,11 +8106,11 @@ function XappDetailPageContent(props) {
7031
8106
  subtitle: title ? t(
7032
8107
  "xapp.history_route_subtitle",
7033
8108
  { title },
7034
- `Recent purchases, invoices, subscriptions, and credit activity for ${title}.`
8109
+ `Balances, recent activity, and purchases for ${title}.`
7035
8110
  ) : t(
7036
8111
  "xapp.history_route_subtitle_default",
7037
8112
  void 0,
7038
- "Recent purchases, invoices, subscriptions, and credit activity for this app."
8113
+ "Balances, recent activity, and purchases for this app."
7039
8114
  ),
7040
8115
  locale,
7041
8116
  showHeader: false
@@ -7046,7 +8121,15 @@ function XappDetailPageContent(props) {
7046
8121
  if (plansOnlyMode) {
7047
8122
  return /* @__PURE__ */ jsxs11("div", { className: `mx-detail-container ${isEmbedded ? "is-embedded" : ""}`, children: [
7048
8123
  error && /* @__PURE__ */ jsx15("div", { className: "mx-detail-error", children: error }),
7049
- busy && !data ? /* @__PURE__ */ jsx15("div", { className: "mx-sidebar-card mx-detail-empty", "aria-busy": "true", children: t("common.loading", void 0, "Loading...") }) : /* @__PURE__ */ jsxs11("div", { className: `mx-plans-route ${widgetHostedPlansMode ? "is-widget-hosted" : ""}`, children: [
8124
+ busy && !data ? /* @__PURE__ */ jsx15("div", { className: "mx-sidebar-card mx-detail-empty mx-plans-route-empty", "aria-busy": "true", children: /* @__PURE__ */ jsxs11("div", { className: "mx-empty-catalog", children: [
8125
+ /* @__PURE__ */ jsx15("div", { className: "mx-empty-catalog-icon", children: "\u25CE" }),
8126
+ /* @__PURE__ */ jsx15("div", { className: "mx-empty-catalog-title", children: t("xapp.plans_loading_title", void 0, "Loading plans") }),
8127
+ /* @__PURE__ */ jsx15("div", { className: "mx-empty-catalog-desc", children: t(
8128
+ "xapp.plans_loading_desc",
8129
+ void 0,
8130
+ "Preparing published plans, balances, and current access for this app."
8131
+ ) })
8132
+ ] }) }) : /* @__PURE__ */ jsxs11("div", { className: `mx-plans-route ${widgetHostedPlansMode ? "is-widget-hosted" : ""}`, children: [
7050
8133
  !widgetHostedPlansMode ? /* @__PURE__ */ jsxs11("div", { className: "mx-breadcrumb", children: [
7051
8134
  /* @__PURE__ */ jsx15(Link10, { to: marketplaceRootHref, children: t("common.marketplace", void 0, "Marketplace") }),
7052
8135
  /* @__PURE__ */ jsx15("span", { className: "mx-breadcrumb-sep", children: "/" }),
@@ -7059,19 +8142,19 @@ function XappDetailPageContent(props) {
7059
8142
  /* @__PURE__ */ jsx15("div", { className: "mx-plans-route-subtitle", children: routeSurfaceView === "history" ? title ? t(
7060
8143
  "xapp.history_route_subtitle",
7061
8144
  { title },
7062
- `Recent purchases, invoices, subscriptions, and credit activity for ${title}.`
8145
+ `Balances, recent activity, and purchases for ${title}.`
7063
8146
  ) : t(
7064
8147
  "xapp.history_route_subtitle_default",
7065
8148
  void 0,
7066
- "Recent purchases, invoices, subscriptions, and credit activity for this app."
8149
+ "Balances, recent activity, and purchases for this app."
7067
8150
  ) : title ? t(
7068
8151
  "xapp.plans_route_subtitle",
7069
8152
  { title },
7070
- `Current access and published plans for ${title}.`
8153
+ `Access, plans, and balances for ${title}.`
7071
8154
  ) : t(
7072
8155
  "xapp.plans_route_subtitle_default",
7073
8156
  void 0,
7074
- "Current access and published plans for this app."
8157
+ "Access, plans, and balances for this app."
7075
8158
  ) })
7076
8159
  ] }) : null,
7077
8160
  /* @__PURE__ */ jsx15("div", { className: "mx-plans-route-grid", children: /* @__PURE__ */ jsxs11("div", { className: "mx-plans-route-main", children: [
@@ -7082,11 +8165,15 @@ function XappDetailPageContent(props) {
7082
8165
  className: "mx-history-route-surface",
7083
8166
  dangerouslySetInnerHTML: { __html: historySurfaceHtml }
7084
8167
  }
7085
- ) : plansCard || /* @__PURE__ */ jsx15("div", { className: "mx-sidebar-card mx-detail-empty", children: t(
7086
- "xapp.no_plans_available",
7087
- void 0,
7088
- "No published plans are currently available."
7089
- ) })
8168
+ ) : plansCard || /* @__PURE__ */ jsx15("div", { className: "mx-sidebar-card mx-detail-empty mx-plans-route-empty", children: /* @__PURE__ */ jsxs11("div", { className: "mx-empty-catalog", children: [
8169
+ /* @__PURE__ */ jsx15("div", { className: "mx-empty-catalog-icon", children: "\u25CE" }),
8170
+ /* @__PURE__ */ jsx15("div", { className: "mx-empty-catalog-title", children: t("xapp.no_plans_available", void 0, "No plans are currently available.") }),
8171
+ /* @__PURE__ */ jsx15("div", { className: "mx-empty-catalog-desc", children: t(
8172
+ "xapp.no_plans_available_desc",
8173
+ void 0,
8174
+ "Published plans will appear here when this app exposes a paywall."
8175
+ ) })
8176
+ ] }) })
7090
8177
  ] }) })
7091
8178
  ] })
7092
8179
  ] });
@@ -7170,9 +8257,9 @@ function XappDetailPageContent(props) {
7170
8257
  description ? /* @__PURE__ */ jsx15("p", { className: "mx-detail-subtitle", children: description }) : null,
7171
8258
  /* @__PURE__ */ jsxs11("div", { className: "mx-detail-meta-row", children: [
7172
8259
  /* @__PURE__ */ jsx15("div", { className: "mx-card-slug", children: xappId }),
7173
- readString5(versionRecord?.version) && /* @__PURE__ */ jsxs11("div", { className: "mx-card-version mx-detail-version-pill", children: [
8260
+ readString6(versionRecord?.version) && /* @__PURE__ */ jsxs11("div", { className: "mx-card-version mx-detail-version-pill", children: [
7174
8261
  "v",
7175
- readString5(versionRecord?.version)
8262
+ readString6(versionRecord?.version)
7176
8263
  ] }),
7177
8264
  updateAvailable ? /* @__PURE__ */ jsx15("div", { className: "mx-detail-update-pill", children: t("xapp.update_available", void 0, "Update available") }) : null
7178
8265
  ] })
@@ -7207,7 +8294,7 @@ function XappDetailPageContent(props) {
7207
8294
  if (requiresTerms) {
7208
8295
  setTermsAccepted(false);
7209
8296
  setTermsAction("install");
7210
- setTermsWidgetId(readString5(defaultWidget?.id) || null);
8297
+ setTermsWidgetId(readString6(defaultWidget?.id) || null);
7211
8298
  setTermsWidgetName(
7212
8299
  resolveMarketplaceText(defaultWidget?.title, locale) || null
7213
8300
  );
@@ -7215,7 +8302,7 @@ function XappDetailPageContent(props) {
7215
8302
  return;
7216
8303
  }
7217
8304
  requestInstallForWidget(
7218
- readString5(defaultWidget?.id) || null,
8305
+ readString6(defaultWidget?.id) || null,
7219
8306
  resolveMarketplaceText(defaultWidget?.title, locale) || null,
7220
8307
  false,
7221
8308
  autoAvailableMode
@@ -7271,7 +8358,7 @@ function XappDetailPageContent(props) {
7271
8358
  void 0,
7272
8359
  "No app views are currently available."
7273
8360
  ) }) : /* @__PURE__ */ jsx15("div", { className: "mx-detail-widget-list", children: widgets.map((w, idx) => {
7274
- const name = resolveMarketplaceText(w.title, locale) || readString5(w.widget_name) || readString5(w.name) || readString5(w.id) || t("common.widget", void 0, "Widget");
8361
+ const name = resolveMarketplaceText(w.title, locale) || readString6(w.widget_name) || readString6(w.name) || readString6(w.id) || t("common.widget", void 0, "Widget");
7275
8362
  const disabled = !widgetsEnabled;
7276
8363
  const isDefault = readBoolean2(w.default, false) || idx === 0 && !widgets.some((ww) => readBoolean2(ww.default, false));
7277
8364
  const widgetType = String(w.type || "").toLowerCase();
@@ -7282,9 +8369,9 @@ function XappDetailPageContent(props) {
7282
8369
  className: `mx-detail-widget-card ${disabled ? "is-disabled" : ""} ${isDefault ? "is-default" : ""}`,
7283
8370
  onClick: () => {
7284
8371
  if (!widgetsEnabled) return;
7285
- const widgetId = readString5(w.id);
8372
+ const widgetId = readString6(w.id);
7286
8373
  if (!widgetId) return;
7287
- launchWidgetForSubject(widgetId, name, readString5(w.bind_tool_name));
8374
+ launchWidgetForSubject(widgetId, name, readString6(w.bind_tool_name));
7288
8375
  },
7289
8376
  children: [
7290
8377
  /* @__PURE__ */ jsx15("div", { className: "mx-detail-widget-icon", children: widgetType === "read" ? /* @__PURE__ */ jsxs11(
@@ -7319,7 +8406,7 @@ function XappDetailPageContent(props) {
7319
8406
  ) }),
7320
8407
  /* @__PURE__ */ jsxs11("div", { className: "mx-detail-widget-body", children: [
7321
8408
  /* @__PURE__ */ jsx15("div", { className: "mx-detail-widget-name", children: name }),
7322
- readString5(w.bind_tool_name) && /* @__PURE__ */ jsx15("div", { className: "mx-detail-widget-tool", children: readString5(w.bind_tool_name) }),
8409
+ readString6(w.bind_tool_name) && /* @__PURE__ */ jsx15("div", { className: "mx-detail-widget-tool", children: readString6(w.bind_tool_name) }),
7323
8410
  /* @__PURE__ */ jsxs11("div", { className: "mx-detail-widget-badges", children: [
7324
8411
  isDefault && /* @__PURE__ */ jsx15("span", { className: "mx-detail-widget-badge is-primary", children: t("xapp.widget_primary", void 0, "Primary") }),
7325
8412
  widgetType && /* @__PURE__ */ jsx15("span", { className: "mx-detail-widget-badge", children: widgetType })
@@ -7609,12 +8696,12 @@ function XappDetailPageContent(props) {
7609
8696
  {
7610
8697
  className: "mx-btn mx-btn-primary mx-detail-primary-cta",
7611
8698
  onClick: () => {
7612
- const widgetId = readString5(defaultWidget.id);
8699
+ const widgetId = readString6(defaultWidget.id);
7613
8700
  if (!widgetId) return;
7614
8701
  launchWidgetForSubject(
7615
8702
  widgetId,
7616
- resolveMarketplaceText(defaultWidget?.title, locale) || readString5(defaultWidget?.widget_name) || readString5(defaultWidget?.name) || t("common.widget", void 0, "Widget"),
7617
- readString5(defaultWidget?.bind_tool_name)
8703
+ resolveMarketplaceText(defaultWidget?.title, locale) || readString6(defaultWidget?.widget_name) || readString6(defaultWidget?.name) || t("common.widget", void 0, "Widget"),
8704
+ readString6(defaultWidget?.bind_tool_name)
7618
8705
  );
7619
8706
  },
7620
8707
  children: openAppLabel
@@ -7834,7 +8921,7 @@ function XappDetailPageContent(props) {
7834
8921
  disabled: !termsAccepted,
7835
8922
  onClick: () => {
7836
8923
  requestInstallForWidget(
7837
- termsWidgetId ?? readString5(defaultWidget?.id) ?? null,
8924
+ termsWidgetId ?? readString6(defaultWidget?.id) ?? null,
7838
8925
  termsWidgetName || resolveMarketplaceText(defaultWidget?.title, locale) || null,
7839
8926
  true,
7840
8927
  autoAvailableMode
@@ -7864,6 +8951,23 @@ function XappDetailPageContent(props) {
7864
8951
  ) : null
7865
8952
  ] })
7866
8953
  ] }) }),
8954
+ /* @__PURE__ */ jsx15(
8955
+ ConfirmActionModal,
8956
+ {
8957
+ open: cancelSubscriptionConfirmOpen,
8958
+ title: t("xapp.subscription_cancel_title", void 0, "Cancel subscription?"),
8959
+ description: t(
8960
+ "xapp.subscription_cancel_description",
8961
+ void 0,
8962
+ "The subscription will stop renewing. Current access remains available until the current period ends."
8963
+ ),
8964
+ confirmLabel: t("xapp.subscription_cancel_action", void 0, "Cancel subscription"),
8965
+ onCancel: () => setCancelSubscriptionConfirmOpen(false),
8966
+ onConfirm: () => {
8967
+ void cancelSubscriptionLifecycle();
8968
+ }
8969
+ }
8970
+ ),
7867
8971
  /* @__PURE__ */ jsx15(
7868
8972
  ConfirmActionModal,
7869
8973
  {
@@ -9114,7 +10218,7 @@ function PublisherDetailPage() {
9114
10218
  {
9115
10219
  to: detailTo,
9116
10220
  className: "mx-btn mx-btn-ghost mx-btn-sm mx-card-footer-link",
9117
- children: "View details"
10221
+ children: t("catalog.view_details", void 0, "View details")
9118
10222
  }
9119
10223
  ) })
9120
10224
  ] }, x.id);