@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.
Files changed (38) hide show
  1. package/package.json +55 -29
  2. package/src/api/pluginRouter.ts +15 -6
  3. package/src/app/[locale]/dashboard/[...pluginRoute]/page.tsx +25 -11
  4. package/src/app/[locale]/dashboard/layout.tsx +30 -30
  5. package/src/app/[locale]/dashboard/preferences/page.tsx +18 -2
  6. package/src/app/[locale]/dashboard/profile/page.tsx +50 -7
  7. package/src/app/globals.css +50 -22
  8. package/src/assets/public/animated-logo-white.svg +0 -0
  9. package/src/assets/public/logo_black.svg +0 -0
  10. package/src/assets/public/logo_white.svg +0 -0
  11. package/src/components/DashboardCatchAll.tsx +16 -8
  12. package/src/components/DashboardRootWrapper.tsx +59 -0
  13. package/src/components/Providers.tsx +56 -22
  14. package/src/components/dashboard/Sidebar.tsx +147 -60
  15. package/src/components/dashboard/Topbar.tsx +56 -25
  16. package/src/config.ts +180 -186
  17. package/src/empty-loader.js +4 -0
  18. package/src/empty.js +5 -0
  19. package/src/index.client.tsx +16 -0
  20. package/src/index.server.tsx +66 -0
  21. package/src/index.tsx +14 -67
  22. package/src/lib/generate-dashboard-metadata.ts +53 -0
  23. package/src/lib/modules-config.ts +0 -2
  24. package/src/lib/plugin-registry.tsx +54 -32
  25. package/src/server.ts +1 -0
  26. package/src/api/README.md +0 -72
  27. package/src/app/[locale]/layout.tsx +0 -28
  28. package/src/app/api/auth/[...nextauth]/route.ts +0 -6
  29. package/src/app/api/plugin-images/list/route.ts +0 -96
  30. package/src/app/api/plugin-images/upload/route.ts +0 -88
  31. package/src/app/api/telemetry/log/route.ts +0 -10
  32. package/src/app/api/telemetry/route.ts +0 -12
  33. package/src/app/api/uploads/[filename]/route.ts +0 -33
  34. package/src/app/layout.tsx +0 -4
  35. package/src/assets/public/Logo_JH_black.jpg +0 -0
  36. package/src/assets/public/Logo_JH_black.png +0 -0
  37. package/src/assets/public/Logo_JH_white.png +0 -0
  38. 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
- const configPath = join(basePath, 'next.config.ts');
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
- // Check if catch-all already exists
25
+ // If it exists, try to inject the dashboard handler
34
26
  if (existsSync(catchAllPath)) {
35
- // Read existing file and check if it already handles dashboard
36
- const fs = await import('fs');
37
- const existingContent = fs.readFileSync(catchAllPath, 'utf8');
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 route that handles dashboard routes
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
- export { default } from '@jhits/dashboard/catch-all';
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
- * Dynamically find all @jhits/* packages from package.json
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 possiblePaths = [
99
- appDir,
100
- join(appDir, '..'),
101
- join(appDir, '..', '..'),
102
- ];
64
+ const packageJsonPath = join(appDir, 'package.json');
65
+ if (!existsSync(packageJsonPath)) return ['@jhits'];
103
66
 
104
- let packageJsonPath: string | null = null;
105
-
106
- for (const basePath of possiblePaths) {
107
- const configPath = join(basePath, 'next.config.ts');
108
- const pkgPath = join(basePath, 'package.json');
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
- // Filter for packages starting with @jhits/
135
- const jhitsPackages = Object.keys(allDeps).filter(
136
- (pkg) => pkg.startsWith('@jhits/')
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
- // Always include the base @jhits pattern for any other packages
140
- return jhitsPackages.length > 0 ? jhitsPackages : ['@jhits'];
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
- // Fallback to wildcard on any error
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
- * JHITS Dashboard Plugin Configuration
150
- *
151
- * Usage:
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
- // Auto-create dashboard routes at build time
159
- // NOTE: User management routes are now handled by plugin-users via the unified plugin router
160
- // No need to auto-generate /api/users routes anymore
161
- if (typeof window === 'undefined') {
162
- try {
163
- ensureDashboardRoutes();
164
- // ensureUserManagementRoutes(); // Disabled - routes are handled by plugin-users via plugin router
165
- } catch {
166
- // Ignore errors - routes might already exist
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
- crypto: false,
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
- buffer: false,
220
- process: false,
221
- // WASI modules
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
- // Prevent server-only packages from being bundled into client
226
- const serverOnlyPackages = [
227
- '@jhits/plugin-dep',
228
- 'nodemailer',
229
- 'mongodb',
230
- 'bcrypt',
231
- 'bcryptjs',
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
  }
@@ -0,0 +1,4 @@
1
+ // Simple loader that returns an empty module for .md files
2
+ module.exports = function(source) {
3
+ return 'module.exports = {};';
4
+ };
package/src/empty.js ADDED
@@ -0,0 +1,5 @@
1
+ // Empty module - used as an alias for modules that should be ignored
2
+ // This is used for WASM virtual modules and other modules that shouldn't be bundled
3
+ // Supports both CommonJS and ES modules for maximum compatibility
4
+ module.exports = {};
5
+ export default {};
@@ -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
- // This exports all the dashboard components and pages that can be used by host apps
3
-
4
- // Router components - inlined to avoid module resolution issues
5
- import DashboardLayout from './app/[locale]/dashboard/layout';
6
- import DashboardHome from './app/[locale]/dashboard/page';
7
- import DashboardPreferences from './app/[locale]/dashboard/preferences/page';
8
- import DashboardProfile from './app/[locale]/dashboard/profile/page';
9
- import DashboardPluginRoute from './app/[locale]/dashboard/[...pluginRoute]/page';
10
-
11
- export async function DashboardRouter({
12
- path,
13
- params
14
- }: {
15
- path: string[];
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