@foldspace-fe/casdoor-next-auth-kit 0.1.15 → 0.1.17

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.
@@ -5,7 +5,7 @@ export { Session } from 'next-auth';
5
5
  import { useSession } from 'next-auth/react';
6
6
  import { A as AuthSession } from '../options-D2YQdRWu.js';
7
7
  export { a as AuthSessionUser, b as AuthTokenPayload } from '../options-D2YQdRWu.js';
8
- import { B as BillingActionPayload, a as BillingItem, b as BillingRuntimeConfig, c as BillingCatalogConfig, d as BillingApiClient, e as BillingLoaders, f as BillingActionExecutor, g as BillingDefaults, h as BillingSubscriptionState, i as BillingSubscriptionHistoryItem, j as BillingProductState, k as BillingOrderHistoryItem, l as BillingPaymentHistoryItem, m as BillingCreditsState, n as BillingEntitlementState, o as BillingStatusState, p as BillingPurchaseStatus, q as BillingProductSnapshot, r as BillingCoreContextValue } from '../types-DwThfdu-.js';
8
+ import { B as BillingActionPayload, a as BillingItem, b as BillingRuntimeConfig, c as BillingCatalogConfig, d as BillingApiClient, e as BillingLoaders, f as BillingActionExecutor, g as BillingDefaults, h as BillingSubscriptionState, i as BillingSubscriptionHistoryItem, j as BillingProductState, k as BillingOrderHistoryItem, l as BillingPaymentHistoryItem, m as BillingCreditsState, n as BillingEntitlementState, o as BillingStatusState, p as BillingPurchaseStatus, q as BillingPurchaseHooks, r as BillingProductSnapshot, s as BillingCasdoorProductDetail, t as BillingCoreContextValue } from '../types-xgHVGy75.js';
9
9
  import 'next-auth/jwt';
10
10
  import '../types-BJv6j3NZ.js';
11
11
 
@@ -60,6 +60,7 @@ interface BillingProviderProps {
60
60
  entitlements?: BillingEntitlementState;
61
61
  status?: BillingStatusState;
62
62
  purchaseStatus?: BillingPurchaseStatus;
63
+ purchaseHooks?: BillingPurchaseHooks;
63
64
  autoRefresh?: boolean;
64
65
  }
65
66
  type BillingCoreProviderProps = BillingProviderProps;
@@ -92,7 +93,7 @@ interface BillingPipelineOptions {
92
93
  }) => Promise<void>;
93
94
  onError?: (error: unknown) => Promise<void>;
94
95
  }
95
- declare function BillingProvider({ children, apiClient, loaders, runtimeConfigLoader, actionExecutor, defaults, runtimeConfig: runtimeConfigProp, subscription: subscriptionProp, subscriptionHistory: subscriptionHistoryProp, products: productsProp, orderHistory: orderHistoryProp, paymentHistory: paymentHistoryProp, credits: creditsProp, entitlements: entitlementsProp, status: statusProp, purchaseStatus: purchaseStatusProp, autoRefresh, }: BillingProviderProps): react_jsx_runtime.JSX.Element;
96
+ declare function BillingProvider({ children, apiClient, loaders, runtimeConfigLoader, actionExecutor, defaults, runtimeConfig: runtimeConfigProp, subscription: subscriptionProp, subscriptionHistory: subscriptionHistoryProp, products: productsProp, orderHistory: orderHistoryProp, paymentHistory: paymentHistoryProp, credits: creditsProp, entitlements: entitlementsProp, status: statusProp, purchaseStatus: purchaseStatusProp, purchaseHooks, autoRefresh, }: BillingProviderProps): react_jsx_runtime.JSX.Element;
96
97
  declare function BillingCoreProvider(props: BillingCoreProviderProps): react_jsx_runtime.JSX.Element;
97
98
  declare function SubscriptionProvider({ children, availablePlans, subscription, subscriptionHistory, entitlements, status, }: BillingSubscriptionProviderProps): react_jsx_runtime.JSX.Element;
98
99
  declare function ProductProvider({ children, availableProducts, products, orderHistory, paymentHistory, status, }: BillingProductProviderProps): react_jsx_runtime.JSX.Element;
@@ -112,6 +113,25 @@ interface BillingItemState {
112
113
  refresh: () => Promise<void>;
113
114
  }
114
115
  declare function useBillingItem(itemKey: string): BillingItemState;
116
+ interface BillingProductDetailState {
117
+ product?: BillingCasdoorProductDetail;
118
+ loading: boolean;
119
+ error: string | null;
120
+ refresh: () => Promise<void>;
121
+ }
122
+ declare function useBillingProductDetail(productId: string): BillingProductDetailState;
123
+ interface BillingProductPurchaseOptionsState {
124
+ product?: BillingCasdoorProductDetail;
125
+ providers: BillingCasdoorProductDetail['providers'];
126
+ providerObjs: BillingCasdoorProductDetail['providerObjs'];
127
+ providerName?: string;
128
+ selectedProvider?: NonNullable<BillingCasdoorProductDetail['providerObjs']>[number];
129
+ setProviderName: (providerName?: string) => void;
130
+ loading: boolean;
131
+ error: string | null;
132
+ refresh: () => Promise<void>;
133
+ }
134
+ declare function useBillingProductPurchaseOptions(productId: string, preferredProviderName?: string): BillingProductPurchaseOptionsState;
115
135
  interface BillingProductsState {
116
136
  products: BillingProductState[];
117
137
  loading: boolean;
@@ -234,4 +254,4 @@ interface BillingProductStateView {
234
254
  declare function useBillingProduct(productKey: string): BillingProductStateView;
235
255
  declare function useBillingCatalogConfig(): BillingCatalogState;
236
256
 
237
- export { type AuthActions, type AuthActionsOptions, AuthProvider, type AuthRole, AuthSession, type AuthUserSummary, type BillingActionHookResult, type BillingAvailablePlansState, type BillingAvailableProductsState, type BillingCatalogState, BillingCoreProvider, type BillingCoreProviderProps, type BillingCreditsProviderProps, type BillingCreditsStateView, type BillingEntitlementsStateView, type BillingItemState, type BillingOrderHistoryState, type BillingPaymentHistoryState, type BillingPipelineOptions, type BillingPipelineResult, type BillingProductProviderProps, type BillingProductStateView, type BillingProductsState, BillingProvider, type BillingProviderProps, type BillingPurchaseStatusView, type BillingRefreshView, type BillingStatusView, type BillingSubscriptionHistoryState, type BillingSubscriptionProductState, type BillingSubscriptionProviderProps, type BillingSubscriptionStateView, CreditsProvider, ProductProvider, SubscriptionProvider, useAuthActions, useAuthRole, useAuthSession, useAuthUser, useBillingAvailablePlans, useBillingAvailableProducts, useBillingCatalog, useBillingCatalogConfig, useBillingContext, useBillingCredits, useBillingEntitlements, useBillingItem, useBillingOrderHistory, useBillingPaymentHistory, useBillingPipeline, useBillingProduct, useBillingProducts, useBillingPurchaseStatus, useBillingRefresh, useBillingStatus, useBillingSubscription, useBillingSubscriptionHistory, useBillingSubscriptionProduct, useCancelSubscription, useManageSubscription, usePurchaseProduct, useSubscribePlan, useUpgradePlan };
257
+ export { type AuthActions, type AuthActionsOptions, AuthProvider, type AuthRole, AuthSession, type AuthUserSummary, type BillingActionHookResult, type BillingAvailablePlansState, type BillingAvailableProductsState, type BillingCatalogState, BillingCoreProvider, type BillingCoreProviderProps, type BillingCreditsProviderProps, type BillingCreditsStateView, type BillingEntitlementsStateView, type BillingItemState, type BillingOrderHistoryState, type BillingPaymentHistoryState, type BillingPipelineOptions, type BillingPipelineResult, type BillingProductDetailState, type BillingProductProviderProps, type BillingProductPurchaseOptionsState, type BillingProductStateView, type BillingProductsState, BillingProvider, type BillingProviderProps, type BillingPurchaseStatusView, type BillingRefreshView, type BillingStatusView, type BillingSubscriptionHistoryState, type BillingSubscriptionProductState, type BillingSubscriptionProviderProps, type BillingSubscriptionStateView, CreditsProvider, ProductProvider, SubscriptionProvider, useAuthActions, useAuthRole, useAuthSession, useAuthUser, useBillingAvailablePlans, useBillingAvailableProducts, useBillingCatalog, useBillingCatalogConfig, useBillingContext, useBillingCredits, useBillingEntitlements, useBillingItem, useBillingOrderHistory, useBillingPaymentHistory, useBillingPipeline, useBillingProduct, useBillingProductDetail, useBillingProductPurchaseOptions, useBillingProducts, useBillingPurchaseStatus, useBillingRefresh, useBillingStatus, useBillingSubscription, useBillingSubscriptionHistory, useBillingSubscriptionProduct, useCancelSubscription, useManageSubscription, usePurchaseProduct, useSubscribePlan, useUpgradePlan };
@@ -1,14 +1,20 @@
1
1
  import {
2
2
  buildBillingActionPayload,
3
+ buildBillingPurchaseRequest,
4
+ buildCasdoorBuyProductRequest,
3
5
  deriveBillingCreditsState,
4
6
  deriveBillingEntitlements,
7
+ filterBillingPurchasableItems,
5
8
  normalizeBillingCatalogConfig,
6
9
  normalizeBillingPurchaseStatus,
7
10
  normalizeBillingRuntimeConfig,
11
+ normalizeCasdoorBuyProductResponse,
12
+ normalizeCasdoorProductId,
8
13
  resolveBillingItem,
9
14
  resolveBillingProductSnapshot,
15
+ resolveBillingPurchasable,
10
16
  resolveBillingSubscriptionProduct
11
- } from "../chunk-O3FKI5NT.js";
17
+ } from "../chunk-46V73LSW.js";
12
18
  import {
13
19
  buildAuthJumpHref
14
20
  } from "../chunk-T2M5MVPE.js";
@@ -92,6 +98,16 @@ function useRequiredCoreContext() {
92
98
  function choose(primary, fallback) {
93
99
  return primary ?? fallback;
94
100
  }
101
+ async function runPurchaseHook(name, hook, context) {
102
+ if (!hook || context === void 0) {
103
+ return;
104
+ }
105
+ try {
106
+ await hook(context);
107
+ } catch (error) {
108
+ console.error(`[casdoor-next-auth-kit] billing ${name} hook failed`, error);
109
+ }
110
+ }
95
111
  function getLatestOrder(orders) {
96
112
  return [...orders ?? []].sort((a, b) => {
97
113
  const left = Date.parse(b.updatedAt ?? b.createdAt ?? "") || 0;
@@ -106,6 +122,55 @@ function getLatestPayment(payments) {
106
122
  return left - right;
107
123
  })[0];
108
124
  }
125
+ function extractCasdoorResponseData(response) {
126
+ if (!response) return void 0;
127
+ if (typeof response === "object" && response !== null && "data" in response) {
128
+ return response.data;
129
+ }
130
+ return response;
131
+ }
132
+ async function runCasdoorProductPurchase(purchaseRequest, apiClient, loaders) {
133
+ const buyProductLoader = loaders?.buyProductLoader ?? apiClient.buyProduct;
134
+ if (!buyProductLoader) {
135
+ return null;
136
+ }
137
+ const productLoader = loaders?.productLoader ?? apiClient.fetchProduct;
138
+ const organizationNamesLoader = loaders?.organizationNamesLoader ?? apiClient.fetchOrganizationNames;
139
+ let productDetail;
140
+ if (productLoader) {
141
+ const productResponse = await productLoader({ id: purchaseRequest.productId }).catch(() => void 0);
142
+ productDetail = extractCasdoorResponseData(productResponse);
143
+ }
144
+ if (!productDetail) {
145
+ if (purchaseRequest.productOwner && purchaseRequest.productName) {
146
+ productDetail = {
147
+ owner: purchaseRequest.productOwner,
148
+ name: purchaseRequest.productName
149
+ };
150
+ } else {
151
+ try {
152
+ const normalized = normalizeCasdoorProductId(purchaseRequest.productId);
153
+ productDetail = {
154
+ owner: normalized.owner,
155
+ name: normalized.name
156
+ };
157
+ } catch {
158
+ return null;
159
+ }
160
+ }
161
+ }
162
+ if (organizationNamesLoader && productDetail.owner) {
163
+ const organizationResponse = await organizationNamesLoader({ owner: productDetail.owner }).catch(() => void 0);
164
+ void extractCasdoorResponseData(organizationResponse);
165
+ }
166
+ const buyRequest = buildCasdoorBuyProductRequest(
167
+ purchaseRequest,
168
+ productDetail,
169
+ purchaseRequest.providerName
170
+ );
171
+ const response = await buyProductLoader(buyRequest);
172
+ return normalizeCasdoorBuyProductResponse(response, purchaseRequest.returnTo ?? productDetail.returnUrl ?? productDetail.successUrl);
173
+ }
109
174
  function normalizeRuntimeConfigInput(config) {
110
175
  if (!config) return void 0;
111
176
  return normalizeBillingRuntimeConfig(config);
@@ -130,9 +195,18 @@ function buildCoreValue(input) {
130
195
  products: input.products,
131
196
  orderHistory: input.orderHistory,
132
197
  paymentHistory: input.paymentHistory,
198
+ availablePlans: filterBillingPurchasableItems(
199
+ input.runtimeConfig?.items?.filter((item) => item.kind === "subscription"),
200
+ input.runtimeConfig ?? input.runtimeCatalog
201
+ ),
202
+ availableProducts: filterBillingPurchasableItems(
203
+ input.runtimeConfig?.items?.filter((item) => item.kind === "product"),
204
+ input.runtimeConfig ?? input.runtimeCatalog
205
+ ),
133
206
  credits: input.credits,
134
207
  entitlements: input.entitlements,
135
208
  purchaseStatus: input.purchaseStatus,
209
+ purchaseHooks: input.purchaseHooks,
136
210
  status: input.status,
137
211
  refresh: input.refresh,
138
212
  runAction: input.runAction,
@@ -165,6 +239,7 @@ function BillingProvider({
165
239
  entitlements: entitlementsProp,
166
240
  status: statusProp,
167
241
  purchaseStatus: purchaseStatusProp,
242
+ purchaseHooks,
168
243
  autoRefresh = true
169
244
  }) {
170
245
  const [runtimeConfig, setRuntimeConfig] = useState(normalizeRuntimeConfigInput(runtimeConfigProp));
@@ -294,6 +369,13 @@ function BillingProvider({
294
369
  async (payload) => {
295
370
  const prepared = buildBillingActionPayload(payload, runtimeConfig);
296
371
  const executor = actionExecutor ?? ((input) => apiClient.createAction(input));
372
+ const isPurchaseFlow = prepared.kind === "purchase" || prepared.kind === "subscribe";
373
+ const purchasable = isPurchaseFlow ? resolveBillingPurchasable(runtimeConfig, prepared.key) ?? resolveBillingPurchasable(runtimeConfig, prepared.productId) : void 0;
374
+ const purchaseRequest = isPurchaseFlow ? buildBillingPurchaseRequest(prepared, runtimeConfig) : null;
375
+ if (isPurchaseFlow && !purchasable) {
376
+ throw new Error(`Billing item "${prepared.key}" is not purchasable in the current runtime config.`);
377
+ }
378
+ await runPurchaseHook("onPurchaseStart", purchaseHooks?.onPurchaseStart, purchaseRequest ?? void 0);
297
379
  setPurchaseStatus((current) => ({
298
380
  actionKey: prepared.key,
299
381
  orderId: current?.orderId,
@@ -305,22 +387,129 @@ function BillingProvider({
305
387
  }));
306
388
  setStatus((current) => ({ ...current, loading: true, refreshing: true, error: null }));
307
389
  try {
308
- const result = await executor(prepared);
390
+ let result;
391
+ let usedCasdoorPurchaseFlow = false;
392
+ if (isPurchaseFlow && purchaseRequest) {
393
+ const casdoorResult = await runCasdoorProductPurchase(
394
+ purchaseRequest,
395
+ apiClient,
396
+ loaders
397
+ );
398
+ if (casdoorResult) {
399
+ result = casdoorResult;
400
+ usedCasdoorPurchaseFlow = true;
401
+ } else {
402
+ result = await executor(prepared);
403
+ }
404
+ } else {
405
+ result = await executor(prepared);
406
+ }
407
+ if (result.status === "failed") {
408
+ await runPurchaseHook(
409
+ "onPurchaseError",
410
+ purchaseHooks?.onPurchaseError,
411
+ purchaseRequest ? {
412
+ request: purchaseRequest,
413
+ orderId: result.orderId ?? null,
414
+ paymentId: result.paymentId ?? null,
415
+ status: "failed",
416
+ message: result.message ?? "Purchase failed.",
417
+ errorCode: result.errorCode,
418
+ redirectTo: result.redirectTo ?? null,
419
+ rawResult: result.rawResult ?? result
420
+ } : void 0
421
+ );
422
+ setPurchaseStatus((current) => ({
423
+ actionKey: prepared.key,
424
+ orderId: result.orderId ?? current?.orderId,
425
+ paymentId: result.paymentId ?? current?.paymentId,
426
+ transactionId: result.transactionId ?? current?.transactionId,
427
+ status: "failed",
428
+ redirectTo: result.redirectTo ?? current?.redirectTo,
429
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
430
+ }));
431
+ setStatus((current) => ({
432
+ ...current,
433
+ loading: false,
434
+ refreshing: false,
435
+ error: result.message ?? current.error ?? "Purchase failed."
436
+ }));
437
+ await runPurchaseHook(
438
+ "onPurchaseComplete",
439
+ purchaseHooks?.onPurchaseComplete,
440
+ purchaseRequest ? {
441
+ request: purchaseRequest,
442
+ orderId: result.orderId ?? null,
443
+ paymentId: result.paymentId ?? null,
444
+ status: "failed",
445
+ redirectTo: result.redirectTo ?? null
446
+ } : void 0
447
+ );
448
+ await refresh();
449
+ return result;
450
+ }
451
+ await runPurchaseHook(
452
+ "onOrderCreated",
453
+ purchaseHooks?.onOrderCreated,
454
+ purchaseRequest && purchasable ? {
455
+ request: purchaseRequest,
456
+ purchasable,
457
+ orderId: result.orderId ?? null,
458
+ paymentId: result.paymentId ?? null,
459
+ redirectTo: result.redirectTo ?? null,
460
+ rawResult: result.rawResult ?? result
461
+ } : void 0
462
+ );
309
463
  setPurchaseStatus((current) => ({
310
464
  actionKey: prepared.key,
311
465
  orderId: current?.orderId,
312
466
  paymentId: current?.paymentId,
313
467
  transactionId: current?.transactionId,
314
- status: result.status === "failed" ? "failed" : result.status === "succeeded" ? "paid" : "pending",
468
+ status: usedCasdoorPurchaseFlow && result.status !== "failed" ? "requires_payment" : result.status === "failed" ? "failed" : result.status === "succeeded" ? "paid" : "pending",
315
469
  redirectTo: result.redirectTo ?? current?.redirectTo,
316
470
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
317
471
  }));
318
472
  if (result.redirectTo || result.nextAction) {
319
473
  }
474
+ await runPurchaseHook(
475
+ "onPurchaseComplete",
476
+ purchaseHooks?.onPurchaseComplete,
477
+ purchaseRequest ? {
478
+ request: purchaseRequest,
479
+ orderId: result.orderId ?? null,
480
+ paymentId: result.paymentId ?? null,
481
+ status: "succeeded",
482
+ redirectTo: result.redirectTo ?? null
483
+ } : void 0
484
+ );
320
485
  await refresh();
321
486
  return result;
322
487
  } catch (error) {
323
488
  const message = error instanceof Error ? error.message : String(error);
489
+ await runPurchaseHook(
490
+ "onPurchaseError",
491
+ purchaseHooks?.onPurchaseError,
492
+ purchaseRequest ? {
493
+ request: purchaseRequest,
494
+ orderId: null,
495
+ paymentId: null,
496
+ status: "failed",
497
+ message,
498
+ redirectTo: null,
499
+ rawResult: error
500
+ } : void 0
501
+ );
502
+ await runPurchaseHook(
503
+ "onPurchaseComplete",
504
+ purchaseHooks?.onPurchaseComplete,
505
+ purchaseRequest ? {
506
+ request: purchaseRequest,
507
+ orderId: null,
508
+ paymentId: null,
509
+ status: "failed",
510
+ redirectTo: null
511
+ } : void 0
512
+ );
324
513
  setPurchaseStatus((current) => ({
325
514
  actionKey: prepared.key,
326
515
  orderId: current?.orderId,
@@ -334,7 +523,7 @@ function BillingProvider({
334
523
  throw error;
335
524
  }
336
525
  },
337
- [actionExecutor, apiClient, refresh, runtimeConfig]
526
+ [actionExecutor, apiClient, loaders, purchaseHooks, refresh, runtimeConfig]
338
527
  );
339
528
  useEffect(() => {
340
529
  if (!autoRefresh) return;
@@ -362,6 +551,7 @@ function BillingProvider({
362
551
  credits,
363
552
  entitlements,
364
553
  purchaseStatus,
554
+ purchaseHooks,
365
555
  status,
366
556
  refresh,
367
557
  runAction,
@@ -386,6 +576,7 @@ function BillingProvider({
386
576
  paymentHistory,
387
577
  products,
388
578
  purchaseStatus,
579
+ purchaseHooks,
389
580
  refresh,
390
581
  runAction,
391
582
  runtimeConfig,
@@ -413,15 +604,20 @@ function SubscriptionProvider({
413
604
  status
414
605
  }) {
415
606
  const core = useOptionalContext(BillingCoreContext);
607
+ const runtimeConfig = core?.runtimeConfig ?? core?.runtimeCatalog;
608
+ const visiblePlans = choose(availablePlans, core?.availablePlans);
416
609
  const value = useMemo(
417
610
  () => ({
418
- availablePlans: choose(availablePlans, core?.runtimeConfig?.items?.filter((item) => item.kind === "subscription")),
611
+ availablePlans: choose(
612
+ visiblePlans ? filterBillingPurchasableItems(visiblePlans, runtimeConfig) : void 0,
613
+ filterBillingPurchasableItems(core?.runtimeConfig?.items?.filter((item) => item.kind === "subscription"), runtimeConfig)
614
+ ),
419
615
  subscription: choose(subscription, core?.subscription),
420
616
  subscriptionHistory: choose(subscriptionHistory, core?.subscriptionHistory),
421
617
  entitlements: choose(entitlements, core?.entitlements),
422
618
  status: choose(status, core?.status)
423
619
  }),
424
- [availablePlans, core?.entitlements, core?.runtimeConfig?.items, core?.status, core?.subscription, core?.subscriptionHistory, entitlements, status, subscription, subscriptionHistory]
620
+ [availablePlans, core?.availablePlans, core?.entitlements, core?.runtimeCatalog, core?.runtimeConfig, core?.status, core?.subscription, core?.subscriptionHistory, entitlements, runtimeConfig, status, subscription, subscriptionHistory, visiblePlans]
425
621
  );
426
622
  return /* @__PURE__ */ jsx2(BillingSubscriptionContext.Provider, { value, children });
427
623
  }
@@ -434,15 +630,20 @@ function ProductProvider({
434
630
  status
435
631
  }) {
436
632
  const core = useOptionalContext(BillingCoreContext);
633
+ const runtimeConfig = core?.runtimeConfig ?? core?.runtimeCatalog;
634
+ const visibleProducts = choose(availableProducts, core?.availableProducts);
437
635
  const value = useMemo(
438
636
  () => ({
439
- availableProducts: choose(availableProducts, core?.runtimeConfig?.items?.filter((item) => item.kind === "product")),
637
+ availableProducts: choose(
638
+ visibleProducts ? filterBillingPurchasableItems(visibleProducts, runtimeConfig) : void 0,
639
+ filterBillingPurchasableItems(core?.runtimeConfig?.items?.filter((item) => item.kind === "product"), runtimeConfig)
640
+ ),
440
641
  products: choose(products, core?.products),
441
642
  orderHistory: choose(orderHistory, core?.orderHistory),
442
643
  paymentHistory: choose(paymentHistory, core?.paymentHistory),
443
644
  status: choose(status, core?.status)
444
645
  }),
445
- [availableProducts, core?.orderHistory, core?.paymentHistory, core?.products, core?.runtimeConfig?.items, core?.status, orderHistory, paymentHistory, products, status]
646
+ [availableProducts, core?.availableProducts, core?.orderHistory, core?.paymentHistory, core?.products, core?.runtimeCatalog, core?.runtimeConfig, core?.status, orderHistory, paymentHistory, products, runtimeConfig, status, visibleProducts]
446
647
  );
447
648
  return /* @__PURE__ */ jsx2(BillingProductContext.Provider, { value, children });
448
649
  }
@@ -484,6 +685,76 @@ function useBillingItem(itemKey) {
484
685
  };
485
686
  }, [core.refresh, core.runtimeConfig?.items, core.runtimeConfigError, core.runtimeConfigLoading, itemKey]);
486
687
  }
688
+ function useBillingProductDetail(productId) {
689
+ const core = useRequiredCoreContext();
690
+ const productLoader = core.loaders?.productLoader ?? core.apiClient.fetchProduct;
691
+ const [product, setProduct] = useState();
692
+ const [loading, setLoading] = useState(false);
693
+ const [error, setError] = useState(null);
694
+ const refresh = useCallback(async () => {
695
+ if (!productLoader || !productId) {
696
+ setProduct(void 0);
697
+ setError(productId ? "Missing Casdoor product loader." : null);
698
+ setLoading(false);
699
+ return;
700
+ }
701
+ setLoading(true);
702
+ setError(null);
703
+ try {
704
+ const response = await productLoader({ id: productId });
705
+ const detail = extractCasdoorResponseData(response);
706
+ setProduct(detail);
707
+ setError(null);
708
+ } catch (err) {
709
+ const message = err instanceof Error ? err.message : String(err);
710
+ setProduct(void 0);
711
+ setError(message);
712
+ } finally {
713
+ setLoading(false);
714
+ }
715
+ }, [productId, productLoader]);
716
+ useEffect(() => {
717
+ void refresh();
718
+ }, [refresh]);
719
+ return useMemo(
720
+ () => ({
721
+ product,
722
+ loading: loading || core.runtimeConfigLoading || core.status.loading,
723
+ error: error ?? core.runtimeConfigError ?? core.status.error,
724
+ refresh
725
+ }),
726
+ [core.runtimeConfigError, core.runtimeConfigLoading, core.status.error, core.status.loading, error, loading, product, refresh]
727
+ );
728
+ }
729
+ function useBillingProductPurchaseOptions(productId, preferredProviderName) {
730
+ const detailState = useBillingProductDetail(productId);
731
+ const [providerName, setProviderName] = useState(preferredProviderName);
732
+ useEffect(() => {
733
+ if (preferredProviderName) {
734
+ setProviderName(preferredProviderName);
735
+ return;
736
+ }
737
+ const product = detailState.product;
738
+ const fallbackProvider = product?.providers?.[0] ?? product?.providerObjs?.[0]?.name;
739
+ if (!providerName || product && !product.providers?.includes(providerName) && !product.providerObjs?.some((item) => item.name === providerName)) {
740
+ setProviderName(fallbackProvider);
741
+ }
742
+ }, [detailState.product, preferredProviderName, providerName]);
743
+ return useMemo(
744
+ () => ({
745
+ product: detailState.product,
746
+ providers: detailState.product?.providers ?? [],
747
+ providerObjs: detailState.product?.providerObjs ?? [],
748
+ providerName,
749
+ selectedProvider: detailState.product?.providerObjs?.find((item) => item.name === providerName),
750
+ setProviderName,
751
+ loading: detailState.loading,
752
+ error: detailState.error,
753
+ refresh: detailState.refresh
754
+ }),
755
+ [detailState.error, detailState.loading, detailState.product, detailState.refresh, providerName]
756
+ );
757
+ }
487
758
  function useBillingProducts() {
488
759
  const core = useRequiredCoreContext();
489
760
  const productContext = useOptionalContext(BillingProductContext);
@@ -501,7 +772,7 @@ function useBillingProducts() {
501
772
  function useBillingAvailablePlans() {
502
773
  const core = useRequiredCoreContext();
503
774
  const subscriptionContext = useOptionalContext(BillingSubscriptionContext);
504
- const plans = choose(subscriptionContext?.availablePlans, core.runtimeConfig?.items?.filter((item) => item.kind === "subscription")) ?? [];
775
+ const plans = choose(subscriptionContext?.availablePlans, core.availablePlans) ?? [];
505
776
  return useMemo(
506
777
  () => ({
507
778
  plans,
@@ -509,13 +780,13 @@ function useBillingAvailablePlans() {
509
780
  error: core.runtimeConfigError ?? core.status.error,
510
781
  refresh: core.refresh
511
782
  }),
512
- [core.refresh, core.runtimeConfig?.items, core.runtimeConfigError, core.runtimeConfigLoading, core.status.error, core.status.loading, plans]
783
+ [core.availablePlans, core.refresh, core.runtimeConfigError, core.runtimeConfigLoading, core.status.error, core.status.loading, plans]
513
784
  );
514
785
  }
515
786
  function useBillingAvailableProducts() {
516
787
  const core = useRequiredCoreContext();
517
788
  const productContext = useOptionalContext(BillingProductContext);
518
- const items = choose(productContext?.availableProducts, core.runtimeConfig?.items?.filter((item) => item.kind === "product")) ?? [];
789
+ const items = choose(productContext?.availableProducts, core.availableProducts) ?? [];
519
790
  return useMemo(
520
791
  () => ({
521
792
  items,
@@ -523,7 +794,7 @@ function useBillingAvailableProducts() {
523
794
  error: core.runtimeConfigError ?? core.status.error,
524
795
  refresh: core.refresh
525
796
  }),
526
- [core.refresh, core.runtimeConfig?.items, core.runtimeConfigError, core.runtimeConfigLoading, core.status.error, core.status.loading, items]
797
+ [core.availableProducts, core.refresh, core.runtimeConfigError, core.runtimeConfigLoading, core.status.error, core.status.loading, items]
527
798
  );
528
799
  }
529
800
  function useBillingOrderHistory(_options = {}) {
@@ -753,6 +1024,8 @@ export {
753
1024
  useBillingPaymentHistory,
754
1025
  useBillingPipeline,
755
1026
  useBillingProduct,
1027
+ useBillingProductDetail,
1028
+ useBillingProductPurchaseOptions,
756
1029
  useBillingProducts,
757
1030
  useBillingPurchaseStatus,
758
1031
  useBillingRefresh,