@jhits/dashboard 0.0.6 → 0.0.8
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 +55 -29
- package/src/api/pluginRouter.ts +15 -6
- package/src/app/[locale]/dashboard/[...pluginRoute]/page.tsx +25 -11
- package/src/app/[locale]/dashboard/layout.tsx +30 -30
- package/src/app/[locale]/dashboard/preferences/page.tsx +18 -2
- package/src/app/[locale]/dashboard/profile/page.tsx +50 -7
- package/src/app/globals.css +50 -22
- package/src/assets/public/animated-logo-white.svg +0 -0
- package/src/assets/public/logo_black.svg +0 -0
- package/src/assets/public/logo_white.svg +0 -0
- package/src/components/DashboardCatchAll.tsx +16 -8
- package/src/components/DashboardRootWrapper.tsx +59 -0
- package/src/components/Providers.tsx +56 -22
- package/src/components/dashboard/Sidebar.tsx +147 -60
- package/src/components/dashboard/Topbar.tsx +56 -25
- package/src/config.ts +180 -186
- package/src/empty-loader.js +4 -0
- package/src/empty.js +5 -0
- package/src/index.client.tsx +16 -0
- package/src/index.server.tsx +66 -0
- package/src/index.tsx +14 -67
- package/src/lib/generate-dashboard-metadata.ts +53 -0
- package/src/lib/modules-config.ts +0 -2
- package/src/lib/plugin-registry.tsx +54 -32
- package/src/server.ts +1 -0
- package/src/api/README.md +0 -72
- package/src/app/[locale]/layout.tsx +0 -28
- package/src/app/api/auth/[...nextauth]/route.ts +0 -6
- package/src/app/api/plugin-images/list/route.ts +0 -96
- package/src/app/api/plugin-images/upload/route.ts +0 -88
- package/src/app/api/telemetry/log/route.ts +0 -10
- package/src/app/api/telemetry/route.ts +0 -12
- package/src/app/api/uploads/[filename]/route.ts +0 -33
- package/src/app/layout.tsx +0 -4
- package/src/assets/public/Logo_JH_black.jpg +0 -0
- package/src/assets/public/Logo_JH_black.png +0 -0
- package/src/assets/public/Logo_JH_white.png +0 -0
- package/src/assets/public/noimagefound.jpg +0 -0
package/src/config.ts
CHANGED
|
@@ -1,26 +1,18 @@
|
|
|
1
1
|
// packages/jhits-dashboard/src/config.ts
|
|
2
2
|
import type { NextConfig } from "next";
|
|
3
|
-
import { writeFileSync, mkdirSync, existsSync, readFileSync } from "fs";
|
|
4
|
-
import { join } from "path";
|
|
3
|
+
import { writeFileSync, mkdirSync, existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Automatically creates a catch-all route that handles dashboard routes
|
|
8
|
-
* This runs at build time when withJhitsDashboard() is called
|
|
9
|
-
* No dashboard folder needed - routes are handled via catch-all at [locale] level
|
|
10
8
|
*/
|
|
11
9
|
async function ensureDashboardRoutes() {
|
|
12
10
|
try {
|
|
13
|
-
// Find the host app directory (where next.config.ts is)
|
|
14
11
|
let appDir = process.cwd();
|
|
15
|
-
const possiblePaths = [
|
|
16
|
-
appDir,
|
|
17
|
-
join(appDir, '..'),
|
|
18
|
-
join(appDir, '..', '..'),
|
|
19
|
-
];
|
|
12
|
+
const possiblePaths = [appDir, join(appDir, '..'), join(appDir, '..', '..')];
|
|
20
13
|
|
|
21
14
|
for (const basePath of possiblePaths) {
|
|
22
|
-
|
|
23
|
-
if (existsSync(configPath)) {
|
|
15
|
+
if (existsSync(join(basePath, 'next.config.ts'))) {
|
|
24
16
|
appDir = basePath;
|
|
25
17
|
break;
|
|
26
18
|
}
|
|
@@ -30,17 +22,11 @@ async function ensureDashboardRoutes() {
|
|
|
30
22
|
const catchAllDir = join(localeDir, '[...path]');
|
|
31
23
|
const catchAllPath = join(catchAllDir, 'page.tsx');
|
|
32
24
|
|
|
33
|
-
//
|
|
25
|
+
// If it exists, try to inject the dashboard handler
|
|
34
26
|
if (existsSync(catchAllPath)) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (existingContent.includes('@jhits/dashboard') || existingContent.includes('DashboardRouter')) {
|
|
39
|
-
// Already set up, skip
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
// If it exists but doesn't handle dashboard, we need to modify it
|
|
43
|
-
// Read the file and prepend dashboard handling
|
|
27
|
+
const existingContent = readFileSync(catchAllPath, 'utf8');
|
|
28
|
+
if (existingContent.includes('@jhits/dashboard') || existingContent.includes('DashboardRouter')) return;
|
|
29
|
+
|
|
44
30
|
const dashboardHandler = `
|
|
45
31
|
// Dashboard route handling (auto-added by @jhits/dashboard)
|
|
46
32
|
if (path.length > 0 && path[0] === 'dashboard') {
|
|
@@ -53,227 +39,235 @@ async function ensureDashboardRoutes() {
|
|
|
53
39
|
);
|
|
54
40
|
}
|
|
55
41
|
`;
|
|
56
|
-
// Insert dashboard handling at the beginning of the function body
|
|
57
42
|
const modifiedContent = existingContent.replace(
|
|
58
43
|
/(export default async function \w+\([^)]+\) \{[\s\S]*?const resolvedParams = await props\.params;[\s\S]*?const path = resolvedParams\.path \|\| \[\];)/,
|
|
59
44
|
`$1${dashboardHandler}`
|
|
60
45
|
);
|
|
61
|
-
|
|
62
|
-
if (modifiedContent !== existingContent) {
|
|
63
|
-
fs.writeFileSync(catchAllPath, modifiedContent);
|
|
64
|
-
} else {
|
|
65
|
-
// If replacement didn't work, append at a safe location
|
|
66
|
-
const safeInsertPoint = existingContent.indexOf('const path = resolvedParams.path');
|
|
67
|
-
if (safeInsertPoint > -1) {
|
|
68
|
-
const before = existingContent.substring(0, safeInsertPoint);
|
|
69
|
-
const after = existingContent.substring(safeInsertPoint);
|
|
70
|
-
const newContent = before + dashboardHandler.trim() + '\n ' + after;
|
|
71
|
-
fs.writeFileSync(catchAllPath, newContent);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
46
|
+
writeFileSync(catchAllPath, modifiedContent);
|
|
74
47
|
return;
|
|
75
48
|
}
|
|
76
49
|
|
|
77
|
-
// Create new catch-all
|
|
50
|
+
// Create new catch-all if none exists
|
|
78
51
|
mkdirSync(catchAllDir, { recursive: true });
|
|
79
|
-
writeFileSync(catchAllPath, `// Auto-generated by @jhits/dashboard - do not edit manually
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
} catch {
|
|
83
|
-
// Silently fail - routes might already exist or be manually created
|
|
52
|
+
writeFileSync(catchAllPath, `// Auto-generated by @jhits/dashboard - do not edit manually\nexport { default } from '@jhits/dashboard/catch-all';\n`);
|
|
53
|
+
} catch (e) {
|
|
54
|
+
console.warn('[@jhits/dashboard] Could not auto-generate dashboard routes:', e);
|
|
84
55
|
}
|
|
85
56
|
}
|
|
86
57
|
|
|
87
58
|
/**
|
|
88
|
-
*
|
|
89
|
-
* Reads dependencies and devDependencies to build transpilePackages list
|
|
90
|
-
*
|
|
91
|
-
* This function finds the app's package.json by looking for next.config.ts
|
|
92
|
-
* in the same directory, ensuring we read from the correct location in monorepos
|
|
59
|
+
* Finds all @jhits/* packages to ensure they are transpiled
|
|
93
60
|
*/
|
|
94
61
|
function findJhitsPackages(): string[] {
|
|
95
62
|
try {
|
|
96
|
-
// Find the app directory (where next.config.ts is located)
|
|
97
63
|
const appDir = process.cwd();
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
join(appDir, '..'),
|
|
101
|
-
join(appDir, '..', '..'),
|
|
102
|
-
];
|
|
64
|
+
const packageJsonPath = join(appDir, 'package.json');
|
|
65
|
+
if (!existsSync(packageJsonPath)) return ['@jhits'];
|
|
103
66
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (existsSync(configPath) && existsSync(pkgPath)) {
|
|
110
|
-
packageJsonPath = pkgPath;
|
|
111
|
-
break;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Fallback to process.cwd() if we can't find next.config.ts
|
|
116
|
-
if (!packageJsonPath) {
|
|
117
|
-
packageJsonPath = join(process.cwd(), 'package.json');
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (!existsSync(packageJsonPath)) {
|
|
121
|
-
// Fallback to wildcard if package.json not found
|
|
122
|
-
return ['@jhits'];
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Use readFileSync instead of require() to avoid module resolution issues
|
|
126
|
-
const packageJsonContent = readFileSync(packageJsonPath, 'utf-8');
|
|
127
|
-
const packageJson = JSON.parse(packageJsonContent);
|
|
128
|
-
|
|
129
|
-
const allDeps = {
|
|
130
|
-
...(packageJson.dependencies || {}),
|
|
131
|
-
...(packageJson.devDependencies || {}),
|
|
132
|
-
};
|
|
67
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
68
|
+
const allDeps = { ...(packageJson.dependencies || {}), ...(packageJson.devDependencies || {}) };
|
|
69
|
+
return Object.keys(allDeps).filter(pkg => pkg.startsWith('@jhits/'));
|
|
70
|
+
} catch { return ['@jhits']; }
|
|
71
|
+
}
|
|
133
72
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Detects if packages are installed from tarballs (file: paths) vs workspace
|
|
75
|
+
* This helps determine if we need special handling for WASM modules
|
|
76
|
+
*/
|
|
77
|
+
function isUsingTarballPackages(): boolean {
|
|
78
|
+
try {
|
|
79
|
+
const appDir = process.cwd();
|
|
80
|
+
const packageJsonPath = join(appDir, 'package.json');
|
|
81
|
+
if (!existsSync(packageJsonPath)) return false;
|
|
138
82
|
|
|
139
|
-
|
|
140
|
-
|
|
83
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
84
|
+
const allDeps = { ...(packageJson.dependencies || {}), ...(packageJson.devDependencies || {}) };
|
|
85
|
+
|
|
86
|
+
// Check if any @jhits package uses file: protocol (tarball installation)
|
|
87
|
+
return Object.entries(allDeps).some(([name, version]) => {
|
|
88
|
+
return name.startsWith('@jhits/') && typeof version === 'string' && version.startsWith('file:');
|
|
89
|
+
});
|
|
141
90
|
} catch {
|
|
142
|
-
|
|
143
|
-
console.warn('[withJhitsDashboard] Could not read package.json, using @jhits wildcard');
|
|
144
|
-
return ['@jhits'];
|
|
91
|
+
return false;
|
|
145
92
|
}
|
|
146
93
|
}
|
|
147
94
|
|
|
148
95
|
/**
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* import { withJhitsDashboard } from '@jhits/dashboard/config';
|
|
153
|
-
* export default withJhitsDashboard(nextConfig);
|
|
154
|
-
*
|
|
155
|
-
* This automatically sets up all dashboard routes - no manual setup needed!
|
|
96
|
+
* Gets the path to empty.js that works in both workspace and tarball modes
|
|
97
|
+
* For Turbopack resolveAlias, we need to use package-relative paths, not absolute paths
|
|
98
|
+
* Turbopack resolves these relative to the package installation location
|
|
156
99
|
*/
|
|
100
|
+
function getEmptyFilePath(): string {
|
|
101
|
+
// Use package-relative path - Turbopack's resolveAlias works better with these
|
|
102
|
+
// The path is resolved via package.json exports, so it works regardless of installation method
|
|
103
|
+
return "@jhits/dashboard/src/empty.js";
|
|
104
|
+
}
|
|
105
|
+
|
|
157
106
|
export function withJhitsDashboard(nextConfig: NextConfig = {}): NextConfig {
|
|
158
|
-
//
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
107
|
+
// Only run file system modifications on the server during initialization
|
|
108
|
+
if (typeof window === 'undefined' && process.env.NEXT_PHASE !== 'phase-production-build') {
|
|
109
|
+
ensureDashboardRoutes().catch(() => { });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Get empty file path - resolve to absolute path for better compatibility
|
|
113
|
+
// This works in both workspace and tarball modes
|
|
114
|
+
// Use absolute path for Turbopack resolveAlias as it's more reliable
|
|
115
|
+
const emptyFile = getEmptyFilePath();
|
|
116
|
+
// Use package-relative path for the loader - Turbopack can resolve this
|
|
117
|
+
// This works both in development (monorepo) and when installed as a package
|
|
118
|
+
const emptyLoaderPath = "@jhits/dashboard/src/empty-loader.js";
|
|
119
|
+
// Detect tarball installation (currently not used but available for future conditional logic)
|
|
120
|
+
const usingTarballs = isUsingTarballPackages();
|
|
121
|
+
|
|
122
|
+
// Log for debugging (only in dev mode)
|
|
123
|
+
if (process.env.NODE_ENV === 'development') {
|
|
124
|
+
console.log('[@jhits/dashboard] Empty file path:', emptyFile);
|
|
125
|
+
console.log('[@jhits/dashboard] Using tarball packages:', usingTarballs);
|
|
168
126
|
}
|
|
169
127
|
|
|
170
128
|
return {
|
|
171
129
|
...nextConfig,
|
|
172
130
|
|
|
173
|
-
// 1. AUTO-TRANSPILE: Dynamically find all @jhits/* packages from package.json
|
|
174
|
-
// This ensures Turbopack knows exactly which workspace folders to link
|
|
175
131
|
transpilePackages: [
|
|
176
132
|
...(nextConfig.transpilePackages || []),
|
|
177
133
|
...findJhitsPackages()
|
|
178
134
|
],
|
|
179
135
|
|
|
136
|
+
turbopack: {
|
|
137
|
+
...nextConfig.turbopack,
|
|
138
|
+
rules: {
|
|
139
|
+
...nextConfig.turbopack?.rules,
|
|
140
|
+
// Handle .md files by treating them as empty JavaScript modules
|
|
141
|
+
// This prevents "Unknown module type" errors for README.md files
|
|
142
|
+
// According to Next.js docs: pattern should be *.md with as: *.js
|
|
143
|
+
// Using our custom empty-loader to return empty module
|
|
144
|
+
// Loaders can be strings (package names or file paths)
|
|
145
|
+
'*.md': {
|
|
146
|
+
loaders: [emptyLoaderPath],
|
|
147
|
+
as: '*.js',
|
|
148
|
+
},
|
|
149
|
+
'*.mdx': {
|
|
150
|
+
loaders: [emptyLoaderPath],
|
|
151
|
+
as: '*.js',
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
resolveAlias: {
|
|
155
|
+
// IMPORTANT: Merge user's resolveAlias FIRST, then apply our aliases
|
|
156
|
+
// This ensures our aliases take precedence for WASM virtual modules
|
|
157
|
+
...nextConfig.turbopack?.resolveAlias,
|
|
158
|
+
// CRITICAL: We only alias specific toxic libraries for CLIENT bundles.
|
|
159
|
+
// We DO NOT alias 'fs', 'path', or 'child_process' here because
|
|
160
|
+
// it breaks the Next.js internal build tools (WASM/SWC).
|
|
161
|
+
// NOTE: mongodb, bcrypt, and nodemailer are handled by serverExternalPackages
|
|
162
|
+
// and should NOT be aliased here as it breaks server-side imports.
|
|
163
|
+
// "mongodb": emptyFile, // REMOVED - breaks server-side imports, use serverExternalPackages instead
|
|
164
|
+
// "bcrypt": emptyFile, // REMOVED - breaks server-side imports, use serverExternalPackages instead
|
|
165
|
+
// "nodemailer": emptyFile, // REMOVED - breaks server-side imports, use serverExternalPackages instead
|
|
166
|
+
// "dns": emptyFile,
|
|
167
|
+
"server-only": emptyFile,
|
|
168
|
+
// Shield the auth logic from the client
|
|
169
|
+
"@jhits/dashboard/lib/auth": emptyFile,
|
|
170
|
+
// WASM virtual modules used by next-intl-swc-plugin-extractor
|
|
171
|
+
// These MUST be aliased AFTER merging user's aliases to ensure they take precedence
|
|
172
|
+
// Required for dev mode (Turbopack) - works in both workspace and tarball mode
|
|
173
|
+
// The empty.js file is exported in package.json and accessible via @jhits/dashboard/src/empty.js
|
|
174
|
+
// In prod mode with webpack, these are handled by webpack.resolve.fallback instead
|
|
175
|
+
"env": emptyFile,
|
|
176
|
+
"wasi_snapshot_preview1": emptyFile,
|
|
177
|
+
// Alias specific .md files to empty file (Turbopack doesn't support wildcards in resolveAlias)
|
|
178
|
+
// Add aliases for known README.md locations in @jhits packages
|
|
179
|
+
"README.md": emptyFile,
|
|
180
|
+
"@jhits/dashboard/README.md": emptyFile,
|
|
181
|
+
"@jhits/plugin-blog/README.md": emptyFile,
|
|
182
|
+
"@jhits/plugin-content/README.md": emptyFile,
|
|
183
|
+
"@jhits/plugin-images/README.md": emptyFile,
|
|
184
|
+
"@jhits/plugin-users/README.md": emptyFile,
|
|
185
|
+
"@jhits/plugin-website/README.md": emptyFile,
|
|
186
|
+
"@jhits/plugin-newsletter/README.md": emptyFile,
|
|
187
|
+
"@jhits/plugin-telemetry/README.md": emptyFile,
|
|
188
|
+
"@jhits/plugin-dep/README.md": emptyFile,
|
|
189
|
+
"@jhits/plugin-core/README.md": emptyFile,
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
|
|
180
193
|
experimental: {
|
|
181
194
|
...nextConfig.experimental,
|
|
182
|
-
// 2. MONOREPO RESOLUTION: This is the secret sauce.
|
|
183
|
-
// It allows Next.js to follow symlinks in the pnpm workspace
|
|
184
|
-
// even if they aren't explicitly listed.
|
|
185
195
|
externalDir: true,
|
|
186
196
|
},
|
|
187
197
|
|
|
188
|
-
// Exclude server-only third-party packages from client bundles
|
|
189
|
-
// Note: @jhits/* packages should NOT be here - they're in transpilePackages instead
|
|
190
|
-
// Adding them here would conflict with transpilePackages in Turbopack
|
|
191
198
|
serverExternalPackages: [
|
|
192
199
|
...(nextConfig.serverExternalPackages || []),
|
|
193
|
-
'mongodb',
|
|
194
|
-
'bcrypt',
|
|
195
|
-
'bcryptjs',
|
|
196
|
-
'jsonwebtoken',
|
|
197
|
-
'nodemailer'
|
|
200
|
+
'mongodb', 'bcrypt', 'bcryptjs', 'jsonwebtoken', 'nodemailer'
|
|
198
201
|
],
|
|
199
202
|
|
|
200
203
|
webpack: (config, { isServer }) => {
|
|
201
|
-
// Ensure Node.js modules are not bundled for client
|
|
202
204
|
if (!isServer) {
|
|
205
|
+
// Webpack is safer for building "fallbacks" than Turbopack's global alias
|
|
203
206
|
config.resolve.fallback = {
|
|
204
207
|
...config.resolve.fallback,
|
|
205
208
|
fs: false,
|
|
206
|
-
path: false,
|
|
207
|
-
'fs/promises': false,
|
|
208
|
-
child_process: false,
|
|
209
209
|
net: false,
|
|
210
210
|
tls: false,
|
|
211
|
-
|
|
212
|
-
stream: false,
|
|
213
|
-
util: false,
|
|
214
|
-
url: false,
|
|
215
|
-
http: false,
|
|
216
|
-
https: false,
|
|
217
|
-
zlib: false,
|
|
211
|
+
child_process: false,
|
|
218
212
|
os: false,
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
//
|
|
213
|
+
// WASM virtual modules used by next-intl-swc-plugin-extractor
|
|
214
|
+
// These are needed when packages are installed from tarballs (file: paths)
|
|
215
|
+
// Using false tells webpack to ignore these modules (works in prod/webpack mode)
|
|
216
|
+
env: false,
|
|
222
217
|
wasi_snapshot_preview1: false,
|
|
223
218
|
};
|
|
224
|
-
|
|
225
|
-
//
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
'
|
|
230
|
-
'
|
|
231
|
-
|
|
232
|
-
'jsonwebtoken',
|
|
233
|
-
];
|
|
234
|
-
|
|
235
|
-
config.externals = config.externals || [];
|
|
236
|
-
if (Array.isArray(config.externals)) {
|
|
237
|
-
config.externals.push(...serverOnlyPackages);
|
|
238
|
-
} else if (typeof config.externals === 'object') {
|
|
239
|
-
serverOnlyPackages.forEach((pkg) => {
|
|
240
|
-
config.externals[pkg] = pkg;
|
|
241
|
-
});
|
|
242
|
-
} else if (typeof config.externals === 'function') {
|
|
243
|
-
const originalExternals = config.externals;
|
|
244
|
-
config.externals = (
|
|
245
|
-
context: string,
|
|
246
|
-
request: string,
|
|
247
|
-
callback: (err?: Error | null, result?: string) => void
|
|
248
|
-
) => {
|
|
249
|
-
if (serverOnlyPackages.includes(request)) {
|
|
250
|
-
return callback(null, `commonjs ${request}`);
|
|
251
|
-
}
|
|
252
|
-
return originalExternals(context, request, callback);
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Ignore server-only plugin files using IgnorePlugin
|
|
257
|
-
// This prevents webpack from trying to bundle server-only files
|
|
258
|
-
try {
|
|
259
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
260
|
-
const webpack = require('webpack');
|
|
261
|
-
config.plugins = config.plugins || [];
|
|
262
|
-
config.plugins.push(
|
|
263
|
-
new webpack.IgnorePlugin({
|
|
264
|
-
resourceRegExp: /^@jhits\/plugin-dep\/src\/(actions|router|index\.server)$/,
|
|
265
|
-
})
|
|
266
|
-
);
|
|
267
|
-
} catch {
|
|
268
|
-
// webpack might not be available in all contexts (e.g., Turbopack)
|
|
269
|
-
// This is fine - the externals and browser field should handle it
|
|
270
|
-
}
|
|
219
|
+
|
|
220
|
+
// Also add to resolve.alias for webpack (backup for Turbopack resolveAlias)
|
|
221
|
+
// This ensures WASM modules are handled even if Turbopack's resolveAlias doesn't work
|
|
222
|
+
config.resolve.alias = {
|
|
223
|
+
...config.resolve.alias,
|
|
224
|
+
'env': false,
|
|
225
|
+
'wasi_snapshot_preview1': false,
|
|
226
|
+
};
|
|
271
227
|
}
|
|
228
|
+
|
|
229
|
+
// Ignore .md files (README.md, etc.) from node_modules
|
|
230
|
+
// This prevents Next.js from trying to process them as modules
|
|
231
|
+
// Note: webpack is only available when using webpack (not Turbopack)
|
|
232
|
+
// Use dynamic require to avoid static analysis issues
|
|
233
|
+
try {
|
|
234
|
+
// Use Function constructor to create a truly dynamic require that won't be statically analyzed
|
|
235
|
+
const requireWebpack = new Function('moduleName', 'return require(moduleName)');
|
|
236
|
+
const webpack = requireWebpack('webpack');
|
|
237
|
+
config.plugins = config.plugins || [];
|
|
238
|
+
// Ignore all .md and .mdx files completely
|
|
239
|
+
config.plugins.push(
|
|
240
|
+
new webpack.IgnorePlugin({
|
|
241
|
+
resourceRegExp: /\.md$/,
|
|
242
|
+
}),
|
|
243
|
+
new webpack.IgnorePlugin({
|
|
244
|
+
resourceRegExp: /\.mdx$/,
|
|
245
|
+
})
|
|
246
|
+
);
|
|
247
|
+
} catch {
|
|
248
|
+
// webpack not available (likely using Turbopack) - skip webpack-specific config
|
|
249
|
+
// This is expected when using Turbopack, so we silently continue
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Add resolve alias for .md files to prevent module resolution errors
|
|
253
|
+
config.resolve.alias = {
|
|
254
|
+
...config.resolve.alias,
|
|
255
|
+
'README.md': false,
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// Add a rule to handle .md files as empty modules if they somehow get imported
|
|
259
|
+
// This is a fallback in case IgnorePlugin doesn't catch everything
|
|
260
|
+
config.module = config.module || {};
|
|
261
|
+
config.module.rules = config.module.rules || [];
|
|
262
|
+
// Insert at the beginning to catch .md files before other rules
|
|
263
|
+
config.module.rules.unshift({
|
|
264
|
+
test: /\.mdx?$/,
|
|
265
|
+
use: {
|
|
266
|
+
loader: require.resolve('./empty-loader.js'),
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
|
|
272
270
|
return config;
|
|
273
271
|
},
|
|
274
|
-
|
|
275
|
-
// Routes are automatically created and managed by the plugin
|
|
276
|
-
// The dashboard folder is completely transparent - you never need to touch it
|
|
277
|
-
// Just use withJhitsDashboard() and everything works!
|
|
278
272
|
};
|
|
279
273
|
}
|
package/src/empty.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Main export file for the dashboard plugin - CLIENT-SAFE ONLY
|
|
2
|
+
// This file should NEVER import or export server-only code
|
|
3
|
+
|
|
4
|
+
'use client';
|
|
5
|
+
|
|
6
|
+
// Client-safe components only
|
|
7
|
+
export { PluginRegistry } from './lib/plugin-registry';
|
|
8
|
+
export { PluginNotFound } from './components/PluginNotFound';
|
|
9
|
+
export { WebsiteProvider, useWebsite } from './lib/website-context';
|
|
10
|
+
export type { WebsiteInfo } from './lib/website-context';
|
|
11
|
+
export { Providers, AuthGuard } from './components/Providers';
|
|
12
|
+
|
|
13
|
+
// Client components
|
|
14
|
+
export { default as Sidebar } from './components/dashboard/Sidebar';
|
|
15
|
+
export { default as Topbar } from './components/dashboard/Topbar';
|
|
16
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Server-only exports for the dashboard plugin
|
|
2
|
+
// This file contains all server-side functionality
|
|
3
|
+
|
|
4
|
+
import 'server-only';
|
|
5
|
+
|
|
6
|
+
// Router components - server-only
|
|
7
|
+
import DashboardLayout from './app/[locale]/dashboard/layout';
|
|
8
|
+
import DashboardHome from './app/[locale]/dashboard/page';
|
|
9
|
+
import DashboardPreferences from './app/[locale]/dashboard/preferences/page';
|
|
10
|
+
import DashboardProfile from './app/[locale]/dashboard/profile/page';
|
|
11
|
+
import DashboardPluginRoute from './app/[locale]/dashboard/[...pluginRoute]/page';
|
|
12
|
+
|
|
13
|
+
export async function DashboardRouter({
|
|
14
|
+
path,
|
|
15
|
+
params
|
|
16
|
+
}: {
|
|
17
|
+
path: string[];
|
|
18
|
+
params: Promise<{ locale: string }>;
|
|
19
|
+
}) {
|
|
20
|
+
const resolvedParams = await params;
|
|
21
|
+
const locale = resolvedParams.locale;
|
|
22
|
+
|
|
23
|
+
// Get the actual route (first segment of path)
|
|
24
|
+
const route = path.length === 0 ? 'home' : path[0];
|
|
25
|
+
|
|
26
|
+
// Handle different dashboard routes
|
|
27
|
+
switch (route) {
|
|
28
|
+
case 'preferences':
|
|
29
|
+
return <DashboardPreferences />;
|
|
30
|
+
case 'profile':
|
|
31
|
+
return <DashboardProfile />;
|
|
32
|
+
case 'home':
|
|
33
|
+
case '':
|
|
34
|
+
return <DashboardHome />;
|
|
35
|
+
default:
|
|
36
|
+
// This is a plugin route - pass the full path as pluginRoute
|
|
37
|
+
return <DashboardPluginRoute params={Promise.resolve({
|
|
38
|
+
locale,
|
|
39
|
+
pluginRoute: path
|
|
40
|
+
})} />;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Layout wrapper
|
|
45
|
+
export function DashboardRouterLayout({ children }: { children: React.ReactNode }) {
|
|
46
|
+
return <DashboardLayout>{children}</DashboardLayout>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Server-only components
|
|
50
|
+
export { default as DashboardCatchAll } from './components/DashboardCatchAll';
|
|
51
|
+
|
|
52
|
+
// Server-only config and utilities
|
|
53
|
+
export { withJhitsDashboard } from './config';
|
|
54
|
+
export { getDashboardMessages } from './i18n/translations';
|
|
55
|
+
export { PLATFORM_MODULES } from './lib/modules-config';
|
|
56
|
+
|
|
57
|
+
// Server-only lib exports (for advanced usage)
|
|
58
|
+
export { authOptions } from './lib/auth';
|
|
59
|
+
export { default as clientPromise } from './lib/mongodb';
|
|
60
|
+
|
|
61
|
+
// API router exports
|
|
62
|
+
export { handlePluginApi, type PluginRouterConfig } from './api/pluginRouter';
|
|
63
|
+
export { handleDashboardApi, createNextRequestFromRequest } from './api/masterRouter';
|
|
64
|
+
|
|
65
|
+
// Metadata generation
|
|
66
|
+
export { generateDashboardMetadata } from './lib/generate-dashboard-metadata';
|
package/src/index.tsx
CHANGED
|
@@ -1,69 +1,16 @@
|
|
|
1
1
|
// Main export file for the dashboard plugin
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
params: Promise<{ locale: string }>;
|
|
17
|
-
}) {
|
|
18
|
-
const resolvedParams = await params;
|
|
19
|
-
const locale = resolvedParams.locale;
|
|
20
|
-
|
|
21
|
-
// Get the actual route (first segment of path)
|
|
22
|
-
const route = path.length === 0 ? 'home' : path[0];
|
|
23
|
-
|
|
24
|
-
// Handle different dashboard routes
|
|
25
|
-
switch (route) {
|
|
26
|
-
case 'preferences':
|
|
27
|
-
return <DashboardPreferences />;
|
|
28
|
-
case 'profile':
|
|
29
|
-
return <DashboardProfile />;
|
|
30
|
-
case 'home':
|
|
31
|
-
case '':
|
|
32
|
-
return <DashboardHome />;
|
|
33
|
-
default:
|
|
34
|
-
// This is a plugin route - pass the full path as pluginRoute
|
|
35
|
-
return <DashboardPluginRoute params={Promise.resolve({
|
|
36
|
-
locale,
|
|
37
|
-
pluginRoute: path
|
|
38
|
-
})} />;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Layout wrapper
|
|
43
|
-
export function DashboardRouterLayout({ children }: { children: React.ReactNode }) {
|
|
44
|
-
return <DashboardLayout>{children}</DashboardLayout>;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Components (for advanced usage)
|
|
48
|
-
export { default as Sidebar } from './components/dashboard/Sidebar';
|
|
49
|
-
export { default as Topbar } from './components/dashboard/Topbar';
|
|
50
|
-
export { PluginNotFound } from './components/PluginNotFound';
|
|
51
|
-
export { Providers, AuthGuard } from './components/Providers';
|
|
52
|
-
|
|
53
|
-
// Plugin system
|
|
54
|
-
export { PluginRegistry } from './lib/plugin-registry';
|
|
55
|
-
export { PLATFORM_MODULES } from './lib/modules-config';
|
|
56
|
-
|
|
57
|
-
// Config
|
|
58
|
-
export { withJhitsDashboard } from './config';
|
|
59
|
-
|
|
60
|
-
// Translations
|
|
61
|
-
export { getDashboardMessages } from './i18n/translations';
|
|
62
|
-
|
|
63
|
-
// Catch-all route handler (for client app integration)
|
|
64
|
-
export { default as DashboardCatchAll } from './components/DashboardCatchAll';
|
|
65
|
-
|
|
66
|
-
// Website context (for accessing website info in dashboard components)
|
|
67
|
-
export { WebsiteProvider, useWebsite } from './lib/website-context';
|
|
68
|
-
export type { WebsiteInfo } from './lib/website-context';
|
|
2
|
+
// Re-exports client-safe code by default
|
|
3
|
+
// For server-only code, import from '@jhits/dashboard/server'
|
|
4
|
+
|
|
5
|
+
// Re-export client-safe code
|
|
6
|
+
export * from './index.client';
|
|
7
|
+
|
|
8
|
+
// Note: Server-only exports are available via '@jhits/dashboard/server'
|
|
9
|
+
// This includes:
|
|
10
|
+
// - DashboardRouter, DashboardRouterLayout
|
|
11
|
+
// - DashboardCatchAll
|
|
12
|
+
// - withJhitsDashboard
|
|
13
|
+
// - getDashboardMessages
|
|
14
|
+
// - PLATFORM_MODULES
|
|
15
|
+
// - authOptions, clientPromise
|
|
69
16
|
|