← Files WixARCHIVED FILE

skills/wix-headless-templates/pricing-plans/project/src/wix/pricing-plans/plan-access-core.ts

1.51 KB · Oct 8, 2026 · 12:02 UTC

↓ Download file

See the change to this file →

// Plan-access (paywall) rules — transport-agnostic, imported by BOTH transports: ./plan-access.ts
// (the SDK) and the REST twin in templates/pricing-plans/rest/plan-access.ts (fetch). What "has
// access" MEANS and what the member-orders read asks for live HERE, once. Type-only imports: a
// strip to JS emits none.
import type { Raw } from "./plans-core";

/** The one order status that grants access: purchased, started, not paused/ended/canceled. */
export const ACCESS_ORDER_STATUSES = ["ACTIVE"] as const;

/** The Member List Orders filter both transports send. */
export interface MemberOrdersQuery {
  planIds: string[];
  orderStatuses: readonly ("ACTIVE")[];
}

/** The filter for "the current member's ACTIVE orders for these plans"; throws on an empty plan list. */
export function memberOrdersQuery(requiredPlanIds: string[]): MemberOrdersQuery {
  if (!requiredPlanIds.length) throw new Error("At least one required plan id is needed to check access.");
  return { planIds: requiredPlanIds, orderStatuses: ACCESS_ORDER_STATUSES };
}

/**
 * Access = the member has at least one order with status ACTIVE whose planId is one of the required
 * plans. Re-checked here even though the query already filtered (a caller may pass orders it read
 * for another reason). Visitors never reach this: they have no orders to list.
 */
export function hasPlanAccess(orders: Raw[] | null | undefined, requiredPlanIds: string[]): boolean {
  return (orders ?? []).some((o) => o?.status === "ACTIVE" && requiredPlanIds.includes(o?.planId));
}

SHA-256: 338355cad4116bdd78e745dc8f5ce0bc61ebb6d80d80faa51a784d19f94e6c49