@moontra/moonui-pro 2.0.23 → 2.1.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moontra/moonui-pro",
3
- "version": "2.0.23",
3
+ "version": "2.1.0",
4
4
  "description": "Premium React components for MoonUI - Advanced UI library with 50+ pro components including performance, interactive, and gesture components",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -16,7 +16,8 @@
16
16
  "sideEffects": [
17
17
  "**/*.css",
18
18
  "dist/**/*.css",
19
- "src/**/*.css"
19
+ "src/**/*.css",
20
+ "src/utils/package-guard.ts"
20
21
  ],
21
22
  "exports": {
22
23
  ".": {
@@ -19,6 +19,7 @@ import {
19
19
  } from 'lucide-react'
20
20
  import { cn } from '../../lib/utils'
21
21
  import { EventDialog } from './event-dialog'
22
+ import { withLicenseGuard } from '../../utils/license-guard'
22
23
 
23
24
  export interface CalendarEvent {
24
25
  id: string
@@ -528,4 +529,29 @@ export function Calendar({
528
529
  )
529
530
  }
530
531
 
531
- export default Calendar
532
+ // Export the component with license guard
533
+ const CalendarWithLicense = withLicenseGuard(Calendar, {
534
+ fallback: (
535
+ <Card className="w-full">
536
+ <CardHeader>
537
+ <CardTitle className="flex items-center gap-2">
538
+ <Lock className="h-5 w-5" />
539
+ Pro Component
540
+ </CardTitle>
541
+ <CardDescription>
542
+ This calendar component requires a MoonUI Pro license.
543
+ </CardDescription>
544
+ </CardHeader>
545
+ <CardContent className="text-center py-8">
546
+ <Button asChild>
547
+ <a href="https://moonui.dev/pricing">
548
+ Get Pro License
549
+ </a>
550
+ </Button>
551
+ </CardContent>
552
+ </Card>
553
+ )
554
+ });
555
+
556
+ export default CalendarWithLicense
557
+ export { Calendar as CalendarCore } // Export unguarded version for internal use
package/src/index.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  // Pro Components Export - Source of Truth: packages/moonui-pro
2
2
  // Development environment imports from local packages
3
3
 
4
+ // Package access guard - ensures CLI usage
5
+ import "./utils/package-guard"
6
+
4
7
  // Import CSS for auto-loading
5
8
  import "./styles/index.css"
6
9
 
@@ -0,0 +1,177 @@
1
+ "use client"
2
+
3
+ import React, { useEffect, useState } from 'react';
4
+
5
+ const API_BASE = process.env.NEXT_PUBLIC_MOONUI_API || 'https://moonui.dev';
6
+
7
+ interface LicenseCheckResult {
8
+ valid: boolean;
9
+ error?: string;
10
+ loading: boolean;
11
+ }
12
+
13
+ // In-memory cache for license check
14
+ let licenseCache: {
15
+ result: boolean;
16
+ timestamp: number;
17
+ } | null = null;
18
+
19
+ const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
20
+
21
+ export function useLicenseCheck(): LicenseCheckResult {
22
+ const [state, setState] = useState<LicenseCheckResult>({
23
+ valid: false,
24
+ loading: true,
25
+ error: undefined
26
+ });
27
+
28
+ useEffect(() => {
29
+ checkLicense().then(result => {
30
+ setState({
31
+ valid: result.valid,
32
+ loading: false,
33
+ error: result.error
34
+ });
35
+ });
36
+ }, []);
37
+
38
+ return state;
39
+ }
40
+
41
+ async function checkLicense(): Promise<{ valid: boolean; error?: string }> {
42
+ // Check cache first
43
+ if (licenseCache && Date.now() - licenseCache.timestamp < CACHE_DURATION) {
44
+ return { valid: licenseCache.result };
45
+ }
46
+
47
+ try {
48
+ // Get auth token from localStorage or cookie
49
+ const token = getAuthToken();
50
+
51
+ if (!token) {
52
+ return { valid: false, error: 'No authentication token found' };
53
+ }
54
+
55
+ const response = await fetch(`${API_BASE}/api/license/verify`, {
56
+ method: 'POST',
57
+ headers: {
58
+ 'Authorization': `Bearer ${token}`,
59
+ 'Content-Type': 'application/json'
60
+ },
61
+ body: JSON.stringify({
62
+ component: 'runtime-check',
63
+ source: 'moonui-pro'
64
+ })
65
+ });
66
+
67
+ if (!response.ok) {
68
+ return { valid: false, error: 'License verification failed' };
69
+ }
70
+
71
+ const data = await response.json();
72
+
73
+ // Cache the result
74
+ licenseCache = {
75
+ result: data.valid && data.planType !== 'free',
76
+ timestamp: Date.now()
77
+ };
78
+
79
+ return { valid: licenseCache.result };
80
+ } catch (error) {
81
+ return { valid: false, error: 'Network error during license check' };
82
+ }
83
+ }
84
+
85
+ function getAuthToken(): string | null {
86
+ // First check localStorage (for client-side)
87
+ if (typeof window !== 'undefined') {
88
+ const stored = localStorage.getItem('moonui_auth');
89
+ if (stored) {
90
+ try {
91
+ const auth = JSON.parse(stored);
92
+ return auth.accessToken;
93
+ } catch {
94
+ // Invalid JSON
95
+ }
96
+ }
97
+ }
98
+
99
+ // Check cookies (for SSR)
100
+ if (typeof document !== 'undefined') {
101
+ const cookies = document.cookie.split(';');
102
+ for (const cookie of cookies) {
103
+ const [name, value] = cookie.trim().split('=');
104
+ if (name === 'moonui_token') {
105
+ return decodeURIComponent(value);
106
+ }
107
+ }
108
+ }
109
+
110
+ return null;
111
+ }
112
+
113
+ // License Guard HOC
114
+ export function withLicenseGuard<P extends object>(
115
+ Component: React.ComponentType<P>,
116
+ options?: {
117
+ fallback?: React.ReactNode;
118
+ onUnauthorized?: () => void;
119
+ }
120
+ ) {
121
+ return function LicenseGuardedComponent(props: P) {
122
+ const { valid, loading, error } = useLicenseCheck();
123
+
124
+ useEffect(() => {
125
+ if (!loading && !valid && options?.onUnauthorized) {
126
+ options.onUnauthorized();
127
+ }
128
+ }, [loading, valid]);
129
+
130
+ if (loading) {
131
+ return (
132
+ <div className="flex items-center justify-center p-8">
133
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"></div>
134
+ </div>
135
+ );
136
+ }
137
+
138
+ if (!valid) {
139
+ if (options?.fallback) {
140
+ return <>{options.fallback}</>;
141
+ }
142
+
143
+ return (
144
+ <div className="rounded-lg border border-red-200 bg-red-50 p-8 text-center">
145
+ <h3 className="text-lg font-semibold text-red-900 mb-2">
146
+ Pro License Required
147
+ </h3>
148
+ <p className="text-red-700 mb-4">
149
+ This component requires a MoonUI Pro license.
150
+ </p>
151
+ <a
152
+ href="https://moonui.dev/pricing"
153
+ className="inline-flex items-center justify-center rounded-md bg-red-600 px-4 py-2 text-sm font-medium text-white hover:bg-red-700"
154
+ >
155
+ Get Pro License
156
+ </a>
157
+ {error && (
158
+ <p className="text-xs text-red-600 mt-4">
159
+ Error: {error}
160
+ </p>
161
+ )}
162
+ </div>
163
+ );
164
+ }
165
+
166
+ return <Component {...props} />;
167
+ };
168
+ }
169
+
170
+ // Self-protecting component wrapper
171
+ export function ProComponent<P extends object>({
172
+ component: Component,
173
+ ...props
174
+ }: P & { component: React.ComponentType<P> }) {
175
+ const GuardedComponent = withLicenseGuard(Component);
176
+ return <GuardedComponent {...(props as P)} />;
177
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Package Access Guard
3
+ * Prevents direct NPM package usage without CLI
4
+ */
5
+
6
+ const ALLOWED_CALLERS = [
7
+ '@moontra/moonui-cli',
8
+ 'moonui-cli',
9
+ '.moonui/temp', // CLI temp directory
10
+ ];
11
+
12
+ const DEV_MODE = process.env.NODE_ENV === 'development';
13
+
14
+ export function checkPackageAccess(): void {
15
+ // Skip in development mode for easier testing
16
+ if (DEV_MODE) {
17
+ return;
18
+ }
19
+
20
+ // Check if running in a browser (client-side)
21
+ if (typeof window !== 'undefined') {
22
+ // Client-side access is allowed after server-side validation
23
+ return;
24
+ }
25
+
26
+ // Server-side check
27
+ const stack = new Error().stack;
28
+
29
+ if (!stack) {
30
+ throw new Error(
31
+ 'MoonUI Pro: This package can only be used via @moontra/moonui-cli. ' +
32
+ 'Please install components using: npx @moontra/moonui-cli add <component>'
33
+ );
34
+ }
35
+
36
+ // Check if called from allowed sources
37
+ const isAllowed = ALLOWED_CALLERS.some(caller => stack.includes(caller));
38
+
39
+ // Also check for local file paths that indicate CLI usage
40
+ const isCliGenerated = stack.includes('/components/ui/') ||
41
+ stack.includes('/components/pro/');
42
+
43
+ if (!isAllowed && !isCliGenerated) {
44
+ console.error('Stack trace:', stack);
45
+ throw new Error(
46
+ 'MoonUI Pro: Unauthorized package access detected.\n' +
47
+ 'This package can only be used via @moontra/moonui-cli.\n' +
48
+ 'Install components using: npx @moontra/moonui-cli add <component>\n\n' +
49
+ 'If you have a Pro license, make sure to:\n' +
50
+ '1. Login with: npx @moontra/moonui-cli login\n' +
51
+ '2. Install components via CLI\n\n' +
52
+ 'Learn more at: https://moonui.dev/docs/installation'
53
+ );
54
+ }
55
+ }
56
+
57
+ // Auto-check on import
58
+ if (typeof window === 'undefined') {
59
+ checkPackageAccess();
60
+ }