@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/dist/index.mjs +215 -214
- package/package.json +3 -2
- package/src/components/calendar/index.tsx +27 -1
- package/src/index.ts +3 -0
- package/src/utils/license-guard.tsx +177 -0
- package/src/utils/package-guard.ts +60 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moontra/moonui-pro",
|
|
3
|
-
"version": "2.0
|
|
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
|
-
|
|
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
|
+
}
|