@vendure/dashboard 3.5.0-minor-202510012036 → 3.5.0-minor-202510031341

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.
@@ -17,10 +17,18 @@ export interface DashboardPluginOptions {
17
17
  route: string;
18
18
  /**
19
19
  * @description
20
- * The path to the dashboard UI app dist directory. By default, the built-in dashboard UI
21
- * will be served. This can be overridden with a custom build of the dashboard.
20
+ * The path to the dashboard UI app dist directory.
22
21
  */
23
22
  appDir: string;
23
+ /**
24
+ * @description
25
+ * The port on which to check for a running Vite dev server.
26
+ * If a Vite dev server is detected on this port, requests will be proxied to it
27
+ * instead of serving static files from appDir.
28
+ *
29
+ * @default 5173
30
+ */
31
+ viteDevServerPort?: number;
24
32
  }
25
33
  /**
26
34
  * @description
@@ -36,10 +44,16 @@ export interface DashboardPluginOptions {
36
44
  * First you need to set up compilation of the Dashboard, using the Vite configuration
37
45
  * described in the [Dashboard Getting Started Guide](/guides/extending-the-dashboard/getting-started/)
38
46
  *
39
- * Once set up, you run `npx vite build` to build the production version of the dashboard app.
47
+ * ## Development vs Production
48
+ *
49
+ * When developing, you can run `npx vite` (or `npm run dev`) to start the Vite development server.
50
+ * The plugin will automatically detect if Vite is running on the default port (5173) and proxy
51
+ * requests to it instead of serving static files. This enables hot module replacement and faster
52
+ * development iterations.
40
53
  *
41
- * The built app files will be output to the location specified by `build.outDir` in your Vite
42
- * config file. This should then be passed to the `appDir` init option, as in the example below:
54
+ * For production, run `npx vite build` to build the dashboard app. The built app files will be
55
+ * output to the location specified by `build.outDir` in your Vite config file. This should then
56
+ * be passed to the `appDir` init option, as in the example below:
43
57
  *
44
58
  * @example
45
59
  * ```ts
@@ -51,6 +65,8 @@ export interface DashboardPluginOptions {
51
65
  * DashboardPlugin.init({
52
66
  * route: 'dashboard',
53
67
  * appDir: './dist/dashboard',
68
+ * // Optional: customize Vite dev server port (defaults to 5173)
69
+ * viteDevServerPort: 3000,
54
70
  * }),
55
71
  * ],
56
72
  * };
@@ -91,5 +107,8 @@ export declare class DashboardPlugin implements NestModule {
91
107
  static init(options: DashboardPluginOptions): Type<DashboardPlugin>;
92
108
  configure(consumer: MiddlewareConsumer): void;
93
109
  private createStaticServer;
94
- private getDashboardPath;
110
+ private checkViteDevServer;
111
+ private checkBuiltFiles;
112
+ private createDefaultPage;
113
+ private createDynamicHandler;
95
114
  }
@@ -1,10 +1,43 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
2
18
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
19
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
20
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
21
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
22
  return c > 3 && r && Object.defineProperty(target, key, r), r;
7
23
  };
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
8
41
  var __metadata = (this && this.__metadata) || function (k, v) {
9
42
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
43
  };
@@ -17,8 +50,9 @@ exports.DashboardPlugin = void 0;
17
50
  const core_1 = require("@vendure/core");
18
51
  const express_1 = __importDefault(require("express"));
19
52
  const express_rate_limit_1 = require("express-rate-limit");
20
- const fs_extra_1 = __importDefault(require("fs-extra"));
21
- const path_1 = __importDefault(require("path"));
53
+ const fs = __importStar(require("node:fs"));
54
+ const http = __importStar(require("node:http"));
55
+ const path = __importStar(require("node:path"));
22
56
  const api_extensions_js_1 = require("./api/api-extensions.js");
23
57
  const metrics_resolver_js_1 = require("./api/metrics.resolver.js");
24
58
  const constants_js_1 = require("./constants.js");
@@ -37,10 +71,16 @@ const metrics_service_js_1 = require("./service/metrics.service.js");
37
71
  * First you need to set up compilation of the Dashboard, using the Vite configuration
38
72
  * described in the [Dashboard Getting Started Guide](/guides/extending-the-dashboard/getting-started/)
39
73
  *
40
- * Once set up, you run `npx vite build` to build the production version of the dashboard app.
74
+ * ## Development vs Production
75
+ *
76
+ * When developing, you can run `npx vite` (or `npm run dev`) to start the Vite development server.
77
+ * The plugin will automatically detect if Vite is running on the default port (5173) and proxy
78
+ * requests to it instead of serving static files. This enables hot module replacement and faster
79
+ * development iterations.
41
80
  *
42
- * The built app files will be output to the location specified by `build.outDir` in your Vite
43
- * config file. This should then be passed to the `appDir` init option, as in the example below:
81
+ * For production, run `npx vite build` to build the dashboard app. The built app files will be
82
+ * output to the location specified by `build.outDir` in your Vite config file. This should then
83
+ * be passed to the `appDir` init option, as in the example below:
44
84
  *
45
85
  * @example
46
86
  * ```ts
@@ -52,6 +92,8 @@ const metrics_service_js_1 = require("./service/metrics.service.js");
52
92
  * DashboardPlugin.init({
53
93
  * route: 'dashboard',
54
94
  * appDir: './dist/dashboard',
95
+ * // Optional: customize Vite dev server port (defaults to 5173)
96
+ * viteDevServerPort: 3000,
55
97
  * }),
56
98
  * ],
57
99
  * };
@@ -98,13 +140,12 @@ let DashboardPlugin = DashboardPlugin_1 = class DashboardPlugin {
98
140
  return;
99
141
  }
100
142
  if (!DashboardPlugin_1.options) {
101
- core_1.Logger.info(`DashboardPlugin's init() method was not called. The Dashboard UI will not be served.`, constants_js_1.loggerCtx);
143
+ core_1.Logger.warn(`DashboardPlugin's init() method was not called. The Dashboard UI will not be served.`, constants_js_1.loggerCtx);
102
144
  return;
103
145
  }
104
- const { route, appDir } = DashboardPlugin_1.options;
105
- const dashboardPath = appDir || this.getDashboardPath();
106
- core_1.Logger.info('Creating dashboard middleware', constants_js_1.loggerCtx);
107
- consumer.apply(this.createStaticServer(dashboardPath)).forRoutes(route);
146
+ const { route, appDir, viteDevServerPort = 5173 } = DashboardPlugin_1.options;
147
+ core_1.Logger.verbose('Creating dashboard middleware', constants_js_1.loggerCtx);
148
+ consumer.apply(this.createDynamicHandler(route, appDir, viteDevServerPort)).forRoutes(route);
108
149
  (0, core_1.registerPluginStartupMessage)('Dashboard UI', route);
109
150
  }
110
151
  createStaticServer(dashboardPath) {
@@ -115,9 +156,6 @@ let DashboardPlugin = DashboardPlugin_1 = class DashboardPlugin {
115
156
  legacyHeaders: false,
116
157
  });
117
158
  const dashboardServer = express_1.default.Router();
118
- // This is a workaround for a type mismatch between express v5 (Vendure core)
119
- // and express v4 (several transitive dependencies). Can be removed once the
120
- // ecosystem has more significantly shifted to v5.
121
159
  dashboardServer.use(limiter);
122
160
  dashboardServer.use(express_1.default.static(dashboardPath));
123
161
  dashboardServer.use((req, res) => {
@@ -125,23 +163,142 @@ let DashboardPlugin = DashboardPlugin_1 = class DashboardPlugin {
125
163
  });
126
164
  return dashboardServer;
127
165
  }
128
- getDashboardPath() {
129
- // First, try to find the dashboard dist directory in the @vendure/dashboard package
166
+ async checkViteDevServer(port) {
167
+ return new Promise(resolve => {
168
+ const req = http.request({
169
+ hostname: 'localhost',
170
+ port,
171
+ path: '/',
172
+ method: 'HEAD',
173
+ timeout: 1000,
174
+ }, (res) => {
175
+ resolve(res.statusCode !== undefined && res.statusCode < 400);
176
+ });
177
+ req.on('error', () => {
178
+ resolve(false);
179
+ });
180
+ req.on('timeout', () => {
181
+ req.destroy();
182
+ resolve(false);
183
+ });
184
+ req.end();
185
+ });
186
+ }
187
+ checkBuiltFiles(appDir) {
130
188
  try {
131
- const dashboardPackageJson = require.resolve('@vendure/dashboard/package.json');
132
- const dashboardPackageRoot = path_1.default.dirname(dashboardPackageJson);
133
- const dashboardDistPath = path_1.default.join(dashboardPackageRoot, 'dist');
134
- if (fs_extra_1.default.existsSync(dashboardDistPath)) {
135
- core_1.Logger.info(`Found dashboard UI at ${dashboardDistPath}`, constants_js_1.loggerCtx);
136
- return dashboardDistPath;
137
- }
189
+ const indexPath = path.join(appDir, 'index.html');
190
+ return fs.existsSync(indexPath);
138
191
  }
139
- catch (e) {
140
- // Dashboard package not found, continue to fallback
192
+ catch (_a) {
193
+ return false;
141
194
  }
142
- // Fallback to default path
143
- core_1.Logger.warn(`Could not find @vendure/dashboard dist directory. Falling back to default path: ${constants_js_1.DEFAULT_APP_PATH}`, constants_js_1.loggerCtx);
144
- return constants_js_1.DEFAULT_APP_PATH;
195
+ }
196
+ createDefaultPage() {
197
+ const limiter = (0, express_rate_limit_1.rateLimit)({
198
+ windowMs: 60 * 1000,
199
+ limit: process.env.NODE_ENV === 'production' ? 500 : 2000,
200
+ standardHeaders: true,
201
+ legacyHeaders: false,
202
+ });
203
+ const defaultPageServer = express_1.default.Router();
204
+ defaultPageServer.use(limiter);
205
+ defaultPageServer.use((req, res) => {
206
+ try {
207
+ const htmlPath = path.join(__dirname, 'default-page.html');
208
+ const defaultHtml = fs.readFileSync(htmlPath, 'utf8');
209
+ res.setHeader('Content-Type', 'text/html');
210
+ res.send(defaultHtml);
211
+ }
212
+ catch (error) {
213
+ res.status(500).send(`Unable to load default page: ${error instanceof Error ? error.message : String(error)}`);
214
+ }
215
+ });
216
+ return defaultPageServer;
217
+ }
218
+ createDynamicHandler(route, appDir, viteDevServerPort) {
219
+ const limiter = (0, express_rate_limit_1.rateLimit)({
220
+ windowMs: 60 * 1000,
221
+ limit: process.env.NODE_ENV === 'production' ? 500 : 2000,
222
+ standardHeaders: true,
223
+ legacyHeaders: false,
224
+ });
225
+ // Pre-create handlers to avoid recreating them on each request
226
+ const proxyHandler = (0, core_1.createProxyHandler)({
227
+ label: 'Dashboard Vite Dev Server',
228
+ route,
229
+ port: viteDevServerPort,
230
+ basePath: route,
231
+ });
232
+ const staticServer = this.createStaticServer(appDir);
233
+ const defaultPage = this.createDefaultPage();
234
+ // Track current mode to log changes
235
+ let currentMode = null;
236
+ const dynamicRouter = express_1.default.Router();
237
+ dynamicRouter.use(limiter);
238
+ // Add status endpoint for polling (localhost only for security)
239
+ dynamicRouter.get('/__status', (req, res, next) => {
240
+ const clientIp = req.ip || req.connection.remoteAddress || req.socket.remoteAddress;
241
+ const isLocalhost = clientIp === '127.0.0.1' ||
242
+ clientIp === '::1' ||
243
+ clientIp === '::ffff:127.0.0.1' ||
244
+ clientIp === 'localhost';
245
+ if (!isLocalhost) {
246
+ return res.status(403).json({ error: 'Access denied' });
247
+ }
248
+ next();
249
+ }, async (req, res) => {
250
+ try {
251
+ const isViteRunning = await this.checkViteDevServer(viteDevServerPort);
252
+ const hasBuiltFiles = this.checkBuiltFiles(appDir);
253
+ const mode = isViteRunning ? 'vite' : hasBuiltFiles ? 'built' : 'default';
254
+ res.json({
255
+ viteRunning: isViteRunning,
256
+ hasBuiltFiles,
257
+ mode,
258
+ });
259
+ }
260
+ catch (error) {
261
+ res.status(500).json({
262
+ error: `Status check failed: ${error instanceof Error ? error.message : String(error)}`,
263
+ });
264
+ }
265
+ });
266
+ dynamicRouter.use(async (req, res, next) => {
267
+ try {
268
+ // Check for Vite dev server first (highest priority)
269
+ const isViteRunning = await this.checkViteDevServer(viteDevServerPort);
270
+ const hasBuiltFiles = this.checkBuiltFiles(appDir);
271
+ // Determine new mode
272
+ const staticMode = hasBuiltFiles ? 'built' : 'default';
273
+ const newMode = isViteRunning ? 'vite' : staticMode;
274
+ // Log mode change
275
+ if (currentMode !== newMode) {
276
+ const modeDescriptions = {
277
+ vite: 'Vite dev server (with HMR)',
278
+ built: 'built static files',
279
+ default: 'default getting-started page',
280
+ };
281
+ if (currentMode !== null) {
282
+ core_1.Logger.info(`Dashboard mode changed: ${currentMode} → ${newMode} (serving ${modeDescriptions[newMode]})`, constants_js_1.loggerCtx);
283
+ }
284
+ currentMode = newMode;
285
+ }
286
+ // Route to appropriate handler
287
+ if (isViteRunning) {
288
+ return proxyHandler(req, res, next);
289
+ }
290
+ if (hasBuiltFiles) {
291
+ return staticServer(req, res, next);
292
+ }
293
+ // Fall back to default page
294
+ return defaultPage(req, res, next);
295
+ }
296
+ catch (error) {
297
+ core_1.Logger.error(`Dashboard dynamic handler error: ${String(error)}`, constants_js_1.loggerCtx);
298
+ res.status(500).send('Dashboard unavailable');
299
+ }
300
+ });
301
+ return dynamicRouter;
145
302
  }
146
303
  };
147
304
  exports.DashboardPlugin = DashboardPlugin;
@@ -0,0 +1,188 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Vendure Dashboard</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ body {
15
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
16
+ background: #000;
17
+ color: #fafafa;
18
+ min-height: 100vh;
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ }
23
+
24
+ .container {
25
+ max-width: 480px;
26
+ width: 90%;
27
+ text-align: center;
28
+ }
29
+
30
+ .logo {
31
+ margin: 40px 80px;
32
+ }
33
+
34
+ h1 {
35
+ font-size: 32px;
36
+ font-weight: 600;
37
+ margin-bottom: 16px;
38
+ letter-spacing: -0.5px;
39
+ }
40
+
41
+ .subtitle {
42
+ font-size: 16px;
43
+ color: #888;
44
+ margin-bottom: 48px;
45
+ line-height: 1.5;
46
+ }
47
+
48
+ .commands {
49
+ display: flex;
50
+ flex-direction: column;
51
+ gap: 12px;
52
+ margin-bottom: 48px;
53
+ }
54
+
55
+ .command {
56
+ background: #111;
57
+ border: 1px solid #333;
58
+ border-radius: 8px;
59
+ padding: 16px 20px;
60
+ text-align: left;
61
+ transition: border-color 0.2s ease;
62
+ }
63
+
64
+ .command:hover {
65
+ border-color: #555;
66
+ }
67
+
68
+ .command-title {
69
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
70
+ font-size: 14px;
71
+ color: #fafafa;
72
+ font-weight: 500;
73
+ margin-bottom: 4px;
74
+ }
75
+
76
+ .command-desc {
77
+ font-size: 13px;
78
+ color: #888;
79
+ }
80
+
81
+ .footer {
82
+ font-size: 14px;
83
+ color: #666;
84
+ }
85
+
86
+ .footer a {
87
+ color: #fafafa;
88
+ text-decoration: none;
89
+ border-bottom: 1px solid transparent;
90
+ transition: border-color 0.2s ease;
91
+ }
92
+
93
+ .footer a:hover {
94
+ border-bottom-color: #fafafa;
95
+ }
96
+
97
+ @media (max-width: 640px) {
98
+ h1 {
99
+ font-size: 28px;
100
+ }
101
+
102
+ .subtitle {
103
+ font-size: 15px;
104
+ }
105
+ }
106
+ </style>
107
+ <link rel="icon" type="image/png" href="data:image/webp;base64,UklGRiwDAABXRUJQVlA4WAoAAAAQAAAAPwAAPwAAQUxQSLUBAAABkMP///lFn2zbtj3bbrdr7tFUZ681XfZ4trlZW7bt+gy/ft/v5/v9j3dDREwA/IuuRaclh35BZ74+jUFhd5GBBLEDO7jdH0MRO7iDO0PxotyvzKFy9pIbj/uVOVTOX/MUYV79E9V/VJqzmFf/RPXftRZUuunPjpD16Emq7lm66c+OkPX4RaYeSWjnJvJu3PZT+HduIO9mdxiB+zck3C1TlO0i4Xd3vtgNvuOX2QYK/cwXx3wbsQTrXH/qLUHVovY317q4hRtewOxxbV6u3ZEE4I4f2pHn5GOxIRAaFL4/keWuHRDb3pGlBawsKCysoEWeK29y9Hn0c95ckakTt/ui2aL7trFTpg5EnLnopuZ2cQYRO0RtciF+rzBTmFV8RyXbJoHHZwI8epyqq5v6+AgJPrrzgdvFWT7E9cHBdVRlmT7vCqTRfdt87GpbPZFArZ/7+kTc8ctsPRBo1fhX1J96SxDsfWupma558YYXiNeK8oBOmk5wj9QCSa/SXAWJbZtG+UabbGUCCGxfZVttDwTZdRLvH6gd3E/UAQ00Lfly1pcSE9BQ55YpxKkWZ9DgiLa2CPjPIQBWUDggUAEAAPAJAJ0BKkAAQAA+jTaVR6UioiEz9N1QoBGJbADOopB+JPKVbU7gH5V3gHmA/gH+S6gHnmdQBz6HsN/uz6S4WB8YK0m3PqfJR8HfqDbB/vlze73BWCg4nAAA/vz4SH/+WDUxM452z3gMx/GuN+7OSD//LCMf/F5Ab5IIDfnWJfU9of/l1cF1H99n//121P/sQ2heGdHI//mL32lEkXNWj6LBhm60ZcgI57R3irC6d/UBmF2HLkHqkpFFGQSGJQUknhOGJeYUlhhNIRy755E+/Al/87y+4t//9cV8xbRIJo9EKQbihU4uLE2PTm9P6yNXTr8O7QFKmSLOh7YHA0+fEidpzooIeFIkMfmzvkh3tWesZNZJjFKs2rHULUUqeMNNkwDLdC4x6UpA9AqbCJYHEj9V6L7eLS2J/teV0a3WWaXoQcRjVkTLy1bsxSowIKAAAA==" />
108
+ </head>
109
+ <body>
110
+ <div class="container">
111
+ <svg viewBox="0 0 539 100" fill="none" xmlns="http://www.w3.org/2000/svg">
112
+ <path d="M198.715 29.7044C198.311 29.1369 197.638 28.7809 196.916 28.7809H189.317C188.393 28.7809 187.547 29.3774 187.239 30.2431L174.3 67.6252L161.16 30.2239C160.862 29.3581 160.034 28.7617 159.082 28.7617H151.261C150.54 28.7617 149.886 29.108 149.462 29.6852C149.058 30.2527 148.962 31.0031 149.183 31.6764L167.817 82.9974C168.115 83.8632 168.942 84.4404 169.866 84.4404H178.139C179.062 84.4404 179.889 83.8728 180.188 82.9974L198.927 31.6764C199.177 31.0031 199.081 30.2623 198.648 29.6852L198.696 29.714L198.715 29.7044Z" fill="#17C1FF"/>
113
+ <path d="M252.778 58.3518C252.855 57.5342 252.903 56.4086 252.903 54.9465C252.903 49.7807 251.729 45.0286 249.43 40.8055C247.131 36.5825 243.88 33.1771 239.839 30.7145C235.77 28.2518 231.143 26.982 226.15 26.982C220.85 26.982 216.031 28.2711 211.836 30.8107C207.642 33.3503 204.343 36.9288 201.995 41.4212C199.667 45.8655 198.494 50.9639 198.494 56.553C198.494 62.142 199.696 67.2404 202.044 71.7135C204.42 76.2156 207.767 79.7941 211.99 82.3241C216.213 84.8636 221.081 86.1527 226.458 86.1527C232.23 86.1527 237.329 84.9887 241.619 82.6511C245.89 80.3135 249.392 77.0621 252.008 72.9834C252.633 71.9925 252.354 70.6746 251.383 70.0012L245.438 66.0476C244.938 65.7205 244.341 65.5955 243.735 65.7205C243.158 65.8456 242.639 66.2207 242.34 66.7113C240.792 69.299 238.695 71.3384 236.145 72.8006C233.596 74.2435 230.277 74.9842 226.256 74.9842C221.456 74.9842 217.791 73.4162 215.04 70.1648C212.644 67.327 211.163 64.0755 210.595 60.2469H250.613C251.739 60.2469 252.691 59.4004 252.787 58.2845V58.3326L252.778 58.3518ZM211.355 49.8288C212.25 46.7986 213.78 44.2397 215.925 42.0753C218.57 39.4395 221.899 38.1505 226.122 38.1505C230.345 38.1505 233.846 39.2664 236.318 41.5558C238.339 43.4413 239.791 46.231 240.59 49.8095H211.336L211.365 49.8384L211.355 49.8288Z" fill="#17C1FF"/>
114
+ <path d="M305.417 36.6883C303.396 33.5042 300.645 31.0512 297.25 29.4062C293.931 27.819 290.227 26.9917 286.331 26.9917C282.108 26.9917 278.337 28.0114 275.086 30.0026C273.758 30.8203 272.537 31.7919 271.44 32.8885V30.9261C271.44 29.7333 270.468 28.7425 269.237 28.7425H261.743C260.541 28.7425 259.54 29.714 259.54 30.9261V82.2471C259.54 83.4399 260.512 84.4308 261.743 84.4308H269.237C270.439 84.4308 271.44 83.4592 271.44 82.2471V56.5722C271.44 50.7811 272.642 46.1348 275.009 42.8064C277.231 39.6704 280.559 38.1312 285.129 38.1312C292.978 38.1312 296.624 42.2773 296.624 51.2044V82.2471C296.624 83.4399 297.596 84.4308 298.827 84.4308H306.321C307.523 84.4308 308.524 83.4592 308.524 82.2471V47.9241C308.524 43.653 307.504 39.8724 305.503 36.6883H305.426H305.417Z" fill="#17C1FF"/>
115
+ <path d="M368.839 0.4702H361.374C360.172 0.4702 359.171 1.44179 359.171 2.66349V32.9655C357.748 31.7149 356.17 30.6279 354.496 29.7525C351.081 27.944 347.253 27.0494 343.183 27.0494C337.893 27.0494 333.073 28.3384 328.869 30.8684C324.675 33.408 321.376 36.9577 319.038 41.4308C316.71 45.8559 315.536 50.9254 315.536 56.5433C315.536 62.1612 316.729 67.3462 319.086 71.8001C321.462 76.2925 324.81 79.8806 329.033 82.4202C333.246 84.9502 338.075 86.2393 343.405 86.2393C347.426 86.2393 351.197 85.3254 354.573 83.4976C356.228 82.6126 357.767 81.5641 359.171 80.3232V82.2856C359.171 83.4784 360.153 84.4692 361.374 84.4692H368.868C370.07 84.4692 371.071 83.4977 371.071 82.2856V2.65386C371.071 1.46102 370.099 0.460571 368.868 0.460571L368.839 0.4702ZM359.171 56.5914C359.171 60.1988 358.469 63.4599 357.074 66.2881C355.699 69.097 353.852 71.2133 351.399 72.7525C348.975 74.2916 346.281 75.0419 343.164 75.0419C340.047 75.0419 337.469 74.3012 335.093 72.7525C332.688 71.2133 330.841 69.0681 329.466 66.2688C328.061 63.431 327.369 60.1507 327.369 56.4663C327.369 52.782 328.071 49.6364 329.466 46.8563C330.841 44.0762 332.688 41.9791 335.093 40.4207C337.46 38.8816 340.115 38.1312 343.164 38.1312C346.214 38.1312 348.984 38.872 351.399 40.4207C353.794 41.931 355.699 44.1147 357.074 46.8851C358.479 49.7133 359.171 52.9744 359.171 56.5818V56.601V56.5914Z" fill="#17C1FF"/>
116
+ <path d="M428.077 28.752H420.583C419.381 28.752 418.381 29.7237 418.381 30.9357V56.5818C418.381 62.3728 417.178 67.0191 414.812 70.3476C412.589 73.4836 409.261 75.0227 404.692 75.0227C396.852 75.0227 393.196 70.8766 393.196 61.9496V30.9069C393.196 29.714 392.225 28.7232 390.993 28.7232H383.5C382.297 28.7232 381.297 29.6948 381.297 30.9069V65.2299C381.297 69.501 382.316 73.2815 384.317 76.4657C386.337 79.6498 389.089 82.1124 392.484 83.7478C395.832 85.335 399.507 86.1623 403.403 86.1623C407.626 86.1623 411.397 85.1426 414.648 83.1513C415.976 82.3337 417.197 81.3909 418.323 80.2654V82.2278C418.323 83.4207 419.294 84.4115 420.526 84.4115H428.019C429.222 84.4115 430.222 83.4399 430.222 82.2278V30.9357C430.222 29.7429 429.251 28.752 428.019 28.752H428.068H428.077Z" fill="#17C1FF"/>
117
+ <path d="M473.049 27.8863C471.221 27.3187 469.297 27.0205 467.325 27.0205C463.054 27.0205 459.177 28.2134 455.762 30.599C454.291 31.6187 452.915 32.8404 451.636 34.2545V30.9742C451.636 29.7814 450.664 28.7905 449.433 28.7905H441.939C440.737 28.7905 439.736 29.7621 439.736 30.9742V82.2952C439.736 83.488 440.708 84.4789 441.939 84.4789H449.433C450.635 84.4789 451.636 83.5073 451.636 82.2952V57.7362C451.636 53.5612 452.386 49.9346 453.887 46.9044C455.358 43.9511 457.311 41.6809 459.687 40.1417C462.063 38.6026 464.555 37.8523 467.306 37.8523C468.826 37.8523 470.182 38.1505 471.433 38.7469C472.106 39.074 472.905 39.0163 473.53 38.6219C474.155 38.2274 474.55 37.5252 474.55 36.7845V29.9738C474.55 29.031 473.924 28.1845 473.03 27.9151L473.059 27.8863H473.049Z" fill="#17C1FF"/>
118
+ <path d="M527.14 58.3518C527.217 57.5342 527.266 56.4375 527.266 54.9465C527.266 49.7807 526.092 45.0093 523.822 40.8055C521.523 36.5825 518.271 33.1771 514.231 30.7145C510.162 28.2518 505.535 27.0109 500.542 27.0109C495.242 27.0109 490.422 28.2999 486.228 30.8395C482.034 33.3791 478.734 36.9577 476.387 41.45C474.069 45.8943 472.885 50.9928 472.885 56.5818C472.885 62.1708 474.088 67.2692 476.435 71.7424C478.811 76.2444 482.159 79.8229 486.401 82.3529C490.624 84.8925 495.492 86.1815 500.869 86.1815C506.641 86.1815 511.739 85.0176 516.03 82.68C520.301 80.3424 523.802 77.091 526.419 73.0122C527.044 72.0214 526.765 70.7035 525.794 70.0301L519.849 66.0764C519.349 65.7494 518.752 65.6243 518.146 65.7494C517.569 65.8744 517.069 66.2496 516.751 66.7402C515.202 69.3279 513.105 71.3672 510.527 72.8294C507.978 74.2724 504.659 75.0131 500.638 75.0131C495.838 75.0131 492.173 73.4451 489.422 70.1936C487.026 67.3558 485.545 64.1044 484.977 60.2758H525.005C526.13 60.2758 527.083 59.4292 527.179 58.3133L527.15 58.3422L527.14 58.3518ZM485.718 49.8288C486.613 46.7986 488.142 44.2397 490.287 42.0753C492.933 39.4395 496.261 38.1505 500.484 38.1505C504.707 38.1505 508.199 39.2664 510.681 41.5558C512.701 43.4413 514.154 46.231 514.952 49.8095H485.699L485.728 49.8384L485.718 49.8288Z" fill="#17C1FF"/>
119
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M530.142 14.8805C526.563 14.8805 523.658 17.7856 523.658 21.3642C523.658 24.9427 526.563 27.8478 530.142 27.8478C533.72 27.8478 536.626 24.9427 536.626 21.3642C536.626 17.7856 533.72 14.8805 530.142 14.8805ZM522.215 21.3642C522.215 16.9872 525.765 13.4375 530.142 13.4375C534.519 13.4375 538.069 16.9872 538.069 21.3642C538.069 25.7411 534.519 29.2908 530.142 29.2908C525.765 29.2908 522.215 25.7411 522.215 21.3642Z" fill="#17C1FF"/>
120
+ <path d="M529.699 20.71C530.142 20.71 530.469 20.6234 530.671 20.4503C530.863 20.2867 530.969 20.0078 530.969 19.623C530.969 19.2382 530.863 18.9688 530.671 18.8053C530.479 18.6418 530.152 18.5648 529.699 18.5648H528.786V20.7196H529.699V20.71ZM528.795 22.201V25.3756H526.631V16.9872H529.93C531.037 16.9872 531.845 17.17 532.354 17.5451C532.874 17.9107 533.124 18.4975 533.124 19.3055C533.124 19.8635 532.989 20.3156 532.73 20.6715C532.46 21.0178 532.066 21.2872 531.518 21.4507C531.816 21.5277 532.075 21.6816 532.316 21.9125C532.556 22.153 532.787 22.5089 533.028 22.9995L534.211 25.3756H531.912L530.883 23.2881C530.681 22.8744 530.469 22.5762 530.257 22.4319C530.046 22.278 529.757 22.1914 529.411 22.1914H528.805L528.795 22.201Z" fill="#17C1FF"/>
121
+ <path d="M34.4303 53.2726V82.7762C34.4303 83.3053 34.7189 83.8055 35.171 84.0652L61.4424 99.2355C62.3851 99.7742 63.5394 99.7742 64.4822 99.2355L90.7535 84.0652C91.2153 83.7959 91.4942 83.3053 91.4942 82.7762V53.2726C91.4942 52.1279 90.2533 51.4064 89.2625 51.9836L64.4822 66.2881C63.5394 66.8268 62.3851 66.8268 61.4424 66.2881L36.6621 51.9836C35.6712 51.4064 34.4303 52.1279 34.4303 53.2726Z" fill="#17C1FF"/>
122
+ <path d="M28.6392 15.2556L2.36781 30.4163C1.42508 30.955 0.8479 31.965 0.8479 33.0425V63.3733C0.8479 63.9024 1.13649 64.4026 1.58862 64.6623L27.1385 79.4189C28.1293 79.9961 29.3702 79.2746 29.3702 78.1299V49.5209C29.3702 48.4339 29.9474 47.4335 30.8902 46.8948L55.6705 32.5903C56.6613 32.0131 56.6613 30.5798 55.6705 30.0122L30.1206 15.2556C29.6588 14.9863 29.0913 14.9863 28.6295 15.2556H28.6392Z" fill="#17C1FF"/>
123
+ <path d="M97.2852 15.2268L123.556 30.3874C124.499 30.9261 125.076 31.9362 125.076 33.0136V63.3444C125.076 63.8735 124.788 64.3737 124.336 64.6335L98.7858 79.3901C97.795 79.9672 96.5541 79.2458 96.5541 78.101V49.4921C96.5541 48.4051 95.9769 47.4046 95.0342 46.8659L70.2539 32.5615C69.263 31.9843 69.263 30.5509 70.2539 29.9834L95.8037 15.2268C96.2655 14.9574 96.833 14.9574 97.2948 15.2268H97.2852Z" fill="#17C1FF"/>
124
+ </svg>
125
+ <p class="subtitle">Build your dashboard or run in development mode to get started.</p>
126
+
127
+ <div class="commands">
128
+ <div class="command">
129
+ <div class="command-title">npx vite</div>
130
+ <div class="command-desc">Start development server</div>
131
+ </div>
132
+ <div class="command">
133
+ <div class="command-title">npx vite build</div>
134
+ <div class="command-desc">Build for production</div>
135
+ </div>
136
+ </div>
137
+
138
+ <div class="footer">
139
+ <a href="https://docs.vendure.io/guides/extending-the-dashboard/getting-started/" target="_blank">Documentation</a>
140
+ </div>
141
+
142
+ <div id="status" style="margin-top: 24px; font-size: 12px; color: #666;">
143
+ Checking for dashboard availability...
144
+ </div>
145
+ </div>
146
+
147
+ <script>
148
+ let pollInterval;
149
+ let statusElement = document.getElementById('status');
150
+
151
+ function pollStatus() {
152
+ fetch('__status')
153
+ .then(response => response.json())
154
+ .then(data => {
155
+ if (data.mode === 'vite') {
156
+ statusElement.textContent = 'Vite dev server detected! Refreshing...';
157
+ statusElement.style.color = '#4ade80';
158
+ setTimeout(() => globalThis.location.reload(), 500);
159
+ } else if (data.mode === 'built') {
160
+ statusElement.textContent = 'Built dashboard detected! Refreshing...';
161
+ statusElement.style.color = '#4ade80';
162
+ setTimeout(() => globalThis.location.reload(), 500);
163
+ } else {
164
+ statusElement.textContent = 'Waiting for dashboard to build or dev server to start...';
165
+ statusElement.style.color = '#666';
166
+ }
167
+ })
168
+ .catch(error => {
169
+ statusElement.textContent = 'Status check failed';
170
+ statusElement.style.color = '#ef4444';
171
+ });
172
+ }
173
+
174
+ // Start polling every 2 seconds
175
+ pollInterval = setInterval(pollStatus, 2000);
176
+
177
+ // Initial check
178
+ pollStatus();
179
+
180
+ // Clean up interval when page unloads
181
+ globalThis.addEventListener('beforeunload', () => {
182
+ if (pollInterval) {
183
+ clearInterval(pollInterval);
184
+ }
185
+ });
186
+ </script>
187
+ </body>
188
+ </html>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vendure/dashboard",
3
3
  "private": false,
4
- "version": "3.5.0-minor-202510012036",
4
+ "version": "3.5.0-minor-202510031341",
5
5
  "type": "module",
6
6
  "repository": {
7
7
  "type": "git",
@@ -106,9 +106,7 @@
106
106
  "@types/react": "^19.0.10",
107
107
  "@types/react-dom": "^19.0.4",
108
108
  "@uidotdev/usehooks": "^2.4.1",
109
- "@vendure/common": "^3.5.0-minor-202510012036",
110
- "@vendure/core": "^3.5.0-minor-202510012036",
111
- "@vitejs/plugin-react": "^4.3.4",
109
+ "@vitejs/plugin-react": "^5.0.4",
112
110
  "@vitejs/plugin-react-swc": "^4.1.0",
113
111
  "acorn": "^8.11.3",
114
112
  "acorn-walk": "^8.3.2",
@@ -121,8 +119,8 @@
121
119
  "express-rate-limit": "^7.5.0",
122
120
  "fast-glob": "^3.3.2",
123
121
  "fs-extra": "^11.2.0",
124
- "gql.tada": "^1.8.10",
125
- "graphql": "^16.10.0",
122
+ "gql.tada": "^1.8.13",
123
+ "graphql": "^16.11.0",
126
124
  "input-otp": "^1.4.2",
127
125
  "json-edit-react": "^1.23.1",
128
126
  "lucide-react": "^0.475.0",
@@ -142,22 +140,24 @@
142
140
  "tsconfig-paths": "^4.2.0",
143
141
  "tw-animate-css": "^1.2.9",
144
142
  "vaul": "^1.1.2",
145
- "vite": "^6.3.5",
143
+ "vite": "^6.3.6",
146
144
  "zod": "^3.25.76"
147
145
  },
148
146
  "devDependencies": {
149
147
  "@eslint/js": "^9.19.0",
150
148
  "@types/node": "^22.13.4",
149
+ "@vendure/common": "^3.5.0-minor-202510031341",
150
+ "@vendure/core": "^3.5.0-minor-202510031341",
151
151
  "eslint": "^9.19.0",
152
152
  "eslint-plugin-react": "^7.37.4",
153
153
  "eslint-plugin-react-hooks": "^5.0.0",
154
154
  "eslint-plugin-react-refresh": "^0.4.18",
155
155
  "globals": "^15.14.0",
156
- "vite-plugin-dts": "^4.5.3"
156
+ "vite-plugin-dts": "^4.5.4"
157
157
  },
158
158
  "optionalDependencies": {
159
159
  "lightningcss-linux-arm64-musl": "^1.29.3",
160
160
  "lightningcss-linux-x64-musl": "^1.29.1"
161
161
  },
162
- "gitHead": "e1ec4b6b65d0743ab1ab1f344eb03c0cf55a7f32"
162
+ "gitHead": "ffe957ddc6b419f17fced0b4b94fe66fc42528f8"
163
163
  }
@@ -3,6 +3,7 @@ import { AccordionContent, AccordionItem, AccordionTrigger } from '@/vdb/compone
3
3
  import { Form } from '@/vdb/components/ui/form.js';
4
4
  import { Input } from '@/vdb/components/ui/input.js';
5
5
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/vdb/components/ui/select.js';
6
+ import { LS_KEY_SHIPPING_TEST_ADDRESS } from '@/vdb/constants.js';
6
7
  import { api } from '@/vdb/graphql/api.js';
7
8
  import { graphql } from '@/vdb/graphql/graphql.js';
8
9
  import { Trans } from '@lingui/react/macro';
@@ -43,20 +44,20 @@ export function TestAddressForm({ onAddressChange }: Readonly<TestAddressFormPro
43
44
  const form = useForm<TestAddress>({
44
45
  defaultValues: (() => {
45
46
  try {
46
- const stored = localStorage.getItem('shippingTestAddress');
47
+ const stored = localStorage.getItem(LS_KEY_SHIPPING_TEST_ADDRESS);
47
48
  return stored
48
49
  ? JSON.parse(stored)
49
50
  : {
50
- fullName: '',
51
- company: '',
52
- streetLine1: '',
53
- streetLine2: '',
54
- city: '',
55
- province: '',
56
- postalCode: '',
57
- countryCode: '',
58
- phoneNumber: '',
59
- };
51
+ fullName: '',
52
+ company: '',
53
+ streetLine1: '',
54
+ streetLine2: '',
55
+ city: '',
56
+ province: '',
57
+ postalCode: '',
58
+ countryCode: '',
59
+ phoneNumber: '',
60
+ };
60
61
  } catch {
61
62
  return {
62
63
  fullName: '',
@@ -92,7 +93,7 @@ export function TestAddressForm({ onAddressChange }: Readonly<TestAddressFormPro
92
93
  previousValuesRef.current = currentValueString;
93
94
 
94
95
  try {
95
- localStorage.setItem('shippingTestAddress', currentValueString);
96
+ localStorage.setItem(LS_KEY_SHIPPING_TEST_ADDRESS, currentValueString);
96
97
  } catch {
97
98
  // Ignore localStorage errors
98
99
  }