@spree/dashboard-core 0.10.0 → 0.10.1

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.
@@ -0,0 +1,89 @@
1
+ import fs from "node:fs";
2
+ import { createRequire } from "node:module";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ function discoverDashboardPluginManifests({ root, onWarn }, names) {
6
+ const require2 = createRequire(path.join(root, "package.json"));
7
+ const candidates = names ?? discoverDashboardPlugins({ root, onWarn });
8
+ const manifests = [];
9
+ for (const name of candidates) {
10
+ const manifestPath = resolveManifest(name, require2);
11
+ if (!manifestPath) {
12
+ manifests.push({ name });
13
+ continue;
14
+ }
15
+ let pkg;
16
+ try {
17
+ pkg = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
18
+ } catch (err) {
19
+ onWarn?.(`Could not parse ${manifestPath}: ${err.message}`);
20
+ manifests.push({ name });
21
+ continue;
22
+ }
23
+ const routes = pkg.spree?.dashboard?.routes;
24
+ manifests.push({
25
+ name,
26
+ routesDir: routes ? path.resolve(path.dirname(manifestPath), routes) : void 0
27
+ });
28
+ }
29
+ return manifests;
30
+ }
31
+ function discoverDashboardPlugins({ root, onWarn }) {
32
+ const hostPkgPath = path.join(root, "package.json");
33
+ if (!fs.existsSync(hostPkgPath)) return [];
34
+ let hostPkg;
35
+ try {
36
+ hostPkg = JSON.parse(fs.readFileSync(hostPkgPath, "utf8"));
37
+ } catch (err) {
38
+ onWarn?.(`Could not parse ${hostPkgPath}: ${err.message}`);
39
+ return [];
40
+ }
41
+ const deps = [
42
+ ...Object.keys(hostPkg.dependencies ?? {}),
43
+ ...Object.keys(hostPkg.devDependencies ?? {})
44
+ ];
45
+ const require2 = createRequire(path.join(root, "package.json"));
46
+ const discovered = [];
47
+ const seen = /* @__PURE__ */ new Set();
48
+ for (const name of deps) {
49
+ if (seen.has(name)) continue;
50
+ seen.add(name);
51
+ const manifestPath = resolveManifest(name, require2);
52
+ if (!manifestPath) continue;
53
+ let depPkg;
54
+ try {
55
+ depPkg = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
56
+ } catch (err) {
57
+ onWarn?.(`Could not parse ${manifestPath}: ${err.message}`);
58
+ continue;
59
+ }
60
+ if (depPkg.spree?.dashboard?.plugin === true) {
61
+ discovered.push(name);
62
+ }
63
+ }
64
+ return discovered;
65
+ }
66
+ function resolveManifest(pkg, require2) {
67
+ try {
68
+ return require2.resolve(`${pkg}/package.json`);
69
+ } catch {
70
+ }
71
+ let entry;
72
+ try {
73
+ entry = require2.resolve(pkg);
74
+ } catch {
75
+ return null;
76
+ }
77
+ let current = path.dirname(entry.startsWith("file:") ? fileURLToPath(entry) : entry);
78
+ const { root } = path.parse(current);
79
+ while (current !== root) {
80
+ const candidate = path.join(current, "package.json");
81
+ if (fs.existsSync(candidate)) return candidate;
82
+ current = path.dirname(current);
83
+ }
84
+ return null;
85
+ }
86
+ export {
87
+ discoverDashboardPluginManifests,
88
+ discoverDashboardPlugins
89
+ };
@@ -0,0 +1,141 @@
1
+ import fs from "node:fs";
2
+ import { createRequire } from "node:module";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import tailwindcss from "@tailwindcss/vite";
6
+ import { discoverDashboardPlugins } from "./discover.js";
7
+ function spreeDashboardPlugin(options = {}) {
8
+ return [dashboardTailwindSourcePlugin(options), tailwindcss()];
9
+ }
10
+ const VIRTUAL_PLUGIN_MODULE_ID = "virtual:spree-dashboard-plugins";
11
+ const RESOLVED_VIRTUAL_PLUGIN_MODULE_ID = `\0${VIRTUAL_PLUGIN_MODULE_ID}`;
12
+ function generateVirtualPluginModule(packages) {
13
+ const header = "// generated by @spree/dashboard-core/vite \u2014 one import per dashboard plugin";
14
+ if (packages.length === 0) return `${header}
15
+ export {}
16
+ `;
17
+ const imports = packages.map((pkg) => `import ${JSON.stringify(pkg)}`).join("\n");
18
+ return `${header}
19
+ ${imports}
20
+ export {}
21
+ `;
22
+ }
23
+ function dashboardTailwindSourcePlugin(options) {
24
+ const explicitPlugins = options.plugins;
25
+ const cssEntry = options.cssEntry ?? "./src/styles.css";
26
+ const fromHere = createRequire(import.meta.url);
27
+ let resolvedSources = [];
28
+ let resolvedCssEntry = "";
29
+ let pluginErrors = [];
30
+ let activatablePlugins = [];
31
+ return {
32
+ name: "spree:dashboard-tailwind-source",
33
+ enforce: "pre",
34
+ configResolved(config) {
35
+ resolvedCssEntry = path.resolve(config.root, cssEntry).split(path.sep).join("/");
36
+ const pluginPackages = explicitPlugins ?? discoverDashboardPlugins({
37
+ root: config.root,
38
+ onWarn: (msg) => console.warn(`[@spree/dashboard-core/vite] ${msg}`)
39
+ });
40
+ const fromHost = createRequire(path.join(config.root, "package.json"));
41
+ pluginErrors = [];
42
+ resolvedSources = [];
43
+ activatablePlugins = [];
44
+ for (const pkg of ["@spree/dashboard-core", "@spree/dashboard-ui"]) {
45
+ const dir = resolvePackageSourceDir(pkg, fromHere);
46
+ if (dir) {
47
+ resolvedSources.push(dir);
48
+ } else {
49
+ pluginErrors.push({ pkg, kind: "unresolved" });
50
+ }
51
+ }
52
+ const shellDir = resolvePackageSourceDir("@spree/dashboard", fromHost);
53
+ if (shellDir) resolvedSources.push(shellDir);
54
+ for (const pkg of pluginPackages) {
55
+ const dir = resolvePackageSourceDir(pkg, fromHost);
56
+ if (dir) {
57
+ resolvedSources.push(dir);
58
+ activatablePlugins.push(pkg);
59
+ } else {
60
+ pluginErrors.push({ pkg, kind: "unresolved" });
61
+ }
62
+ }
63
+ },
64
+ resolveId(id) {
65
+ if (id === VIRTUAL_PLUGIN_MODULE_ID) return RESOLVED_VIRTUAL_PLUGIN_MODULE_ID;
66
+ return null;
67
+ },
68
+ load(id) {
69
+ if (id !== RESOLVED_VIRTUAL_PLUGIN_MODULE_ID) return null;
70
+ return generateVirtualPluginModule(activatablePlugins);
71
+ },
72
+ transform(code, id) {
73
+ const normalized = id.split("?")[0].replaceAll("\\", "/");
74
+ if (normalized !== resolvedCssEntry) return null;
75
+ const directives = resolvedSources.map((dir) => `@source '${dir}';`).join("\n");
76
+ return {
77
+ code: `${code}
78
+
79
+ /* injected by @spree/dashboard-core/vite */
80
+ ${directives}
81
+ `,
82
+ map: null
83
+ };
84
+ },
85
+ configureServer(server) {
86
+ if (pluginErrors.length === 0) return;
87
+ const message = formatPluginErrorOverlay(pluginErrors);
88
+ server.ws.on("connection", () => {
89
+ server.ws.send({
90
+ type: "error",
91
+ err: {
92
+ message,
93
+ stack: "",
94
+ plugin: "spree:dashboard-tailwind-source"
95
+ }
96
+ });
97
+ });
98
+ }
99
+ };
100
+ }
101
+ function formatPluginErrorOverlay(errors) {
102
+ const lines = [
103
+ "Spree dashboard plugin(s) could not be resolved:",
104
+ "",
105
+ ...errors.map(({ pkg }) => ` - ${pkg}`),
106
+ "",
107
+ "For each one, check:",
108
+ " 1. The package is installed (`pnpm add <package>`)",
109
+ " 2. Its package.json declares the dashboard marker:",
110
+ ' { "spree": { "dashboard": { "plugin": true } } }',
111
+ "",
112
+ "If you registered it explicitly via spreeDashboardPlugin({ plugins: [...] }),",
113
+ "verify the name matches the installed package exactly."
114
+ ];
115
+ return lines.join("\n");
116
+ }
117
+ function resolvePackageSourceDir(pkg, require2) {
118
+ try {
119
+ const entryPath = require2.resolve(pkg);
120
+ const entryFile = entryPath.startsWith("file:") ? fileURLToPath(entryPath) : entryPath;
121
+ const packageRoot = findPackageRoot(entryFile);
122
+ if (!packageRoot) return null;
123
+ return path.join(packageRoot, "src");
124
+ } catch {
125
+ return null;
126
+ }
127
+ }
128
+ function findPackageRoot(fromFile) {
129
+ let current = path.dirname(fromFile);
130
+ const { root } = path.parse(current);
131
+ while (current !== root) {
132
+ if (fs.existsSync(path.join(current, "package.json"))) return current;
133
+ current = path.dirname(current);
134
+ }
135
+ return null;
136
+ }
137
+ export {
138
+ VIRTUAL_PLUGIN_MODULE_ID,
139
+ generateVirtualPluginModule,
140
+ spreeDashboardPlugin
141
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@spree/dashboard-core",
3
3
  "license": "MIT",
4
- "version": "0.10.0",
4
+ "version": "0.10.1",
5
5
  "description": "Spree Dashboard framework — registries (table, nav, slot, settings-nav), providers (auth, permission, store), admin SDK client, generic infra hooks, and the defineDashboardPlugin extension API. Developer Preview.",
6
6
  "author": "Vendo Connect Inc.",
7
7
  "homepage": "https://spreecommerce.org",
@@ -26,8 +26,14 @@
26
26
  "exports": {
27
27
  ".": "./src/index.ts",
28
28
  "./plugin": "./src/plugin.ts",
29
- "./vite": "./src/vite/index.ts",
30
- "./vite/discover": "./src/vite/discover.ts",
29
+ "./vite": {
30
+ "types": "./src/vite/index.ts",
31
+ "default": "./dist/vite/index.js"
32
+ },
33
+ "./vite/discover": {
34
+ "types": "./src/vite/discover.ts",
35
+ "default": "./dist/vite/discover.js"
36
+ },
31
37
  "./providers/*": "./src/providers/*.tsx",
32
38
  "./hooks/*": "./src/hooks/*.ts",
33
39
  "./hooks/use-command-palette": "./src/hooks/use-command-palette.tsx",
@@ -36,6 +42,7 @@
36
42
  },
37
43
  "files": [
38
44
  "src",
45
+ "dist",
39
46
  "README.md",
40
47
  "LICENSE"
41
48
  ],
@@ -50,7 +57,7 @@
50
57
  "react-hook-form": "^7.75.0",
51
58
  "react-i18next": "^17.0.8",
52
59
  "sonner": "^2.0.7",
53
- "@spree/admin-sdk": "^0.5.0",
60
+ "@spree/admin-sdk": "^0.6.0",
54
61
  "@spree/dashboard-ui": "^0.10.0"
55
62
  },
56
63
  "dependencies": {
@@ -68,10 +75,11 @@
68
75
  "@types/react": "^19.2.14",
69
76
  "@types/react-dom": "^19.2.3",
70
77
  "@types/spark-md5": "^3.0.5",
78
+ "tsup": "^8.5.1",
71
79
  "typescript": "~6.0.3",
72
80
  "vite": "^8.0.16",
73
81
  "vitest": "^4.1.5",
74
- "@spree/admin-sdk": "^0.5.0",
82
+ "@spree/admin-sdk": "^0.6.0",
75
83
  "@spree/dashboard-ui": "^0.10.0"
76
84
  },
77
85
  "scripts": {
@@ -79,6 +87,7 @@
79
87
  "lint:fix": "biome check --fix src",
80
88
  "format": "biome format --write src",
81
89
  "typecheck": "tsc --noEmit",
82
- "test": "vitest run"
90
+ "test": "vitest run",
91
+ "build": "tsup"
83
92
  }
84
93
  }
package/src/vite/index.ts CHANGED
@@ -2,13 +2,12 @@ import fs from 'node:fs'
2
2
  import { createRequire } from 'node:module'
3
3
  import path from 'node:path'
4
4
  import { fileURLToPath } from 'node:url'
5
- // Self-referencing package import (not a relative path): this entry is loaded
6
- // raw by Node when a host's vite.config.ts imports `@spree/dashboard-core/vite`,
7
- // and Node's TS type-stripping can't resolve extensionless relative specifiers.
8
- // The exports-map path resolves to the real file name everywhere.
9
- import { discoverDashboardPlugins } from '@spree/dashboard-core/vite/discover'
10
5
  import tailwindcss from '@tailwindcss/vite'
11
6
  import type { Plugin, PluginOption } from 'vite'
7
+ // Explicit .js extension: this entry ships compiled (dist/vite), where the
8
+ // specifier must name the real emitted file — tsup transpiles 1:1 without
9
+ // rewriting import paths. Bundlers map .js back to the .ts source.
10
+ import { discoverDashboardPlugins } from './discover.js'
12
11
 
13
12
  export interface SpreeDashboardPluginOptions {
14
13
  /**