spine-framework 0.1.61 → 0.2.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.
package/.framework/src/App.tsx
CHANGED
|
@@ -67,13 +67,17 @@ function AuthenticatedRouter() {
|
|
|
67
67
|
return (b.route_prefix?.length || 0) - (a.route_prefix?.length || 0)
|
|
68
68
|
})
|
|
69
69
|
|
|
70
|
+
// When an app is mounted at root it owns all routes — suppress the
|
|
71
|
+
// framework's own /dashboard and catch-all 404 to avoid conflicts.
|
|
72
|
+
const hasRootApp = sorted.some(app => app.route_prefix === '/')
|
|
73
|
+
|
|
70
74
|
return (
|
|
71
75
|
<Suspense fallback={<div className="min-h-screen flex items-center justify-center"><LoadingSpinner /></div>}>
|
|
72
76
|
<Routes>
|
|
73
|
-
{/* Default redirect */}
|
|
74
|
-
<Route path="/" element={<Navigate to="/dashboard" replace />} />
|
|
75
|
-
<Route path="/dashboard" element={<DashboardPage />} />
|
|
76
|
-
|
|
77
|
+
{/* Default redirect — suppressed when a root app is installed */}
|
|
78
|
+
{!hasRootApp && <Route path="/" element={<Navigate to="/dashboard" replace />} />}
|
|
79
|
+
{!hasRootApp && <Route path="/dashboard" element={<DashboardPage />} />}
|
|
80
|
+
|
|
77
81
|
{/* Login route for authenticated users (redirects to qualified app) */}
|
|
78
82
|
<Route path="/login" element={<LoginPage />} />
|
|
79
83
|
|
|
@@ -85,12 +89,14 @@ function AuthenticatedRouter() {
|
|
|
85
89
|
{/* Dynamic app routes */}
|
|
86
90
|
{sorted.map(app => {
|
|
87
91
|
const prefix = app.route_prefix!
|
|
92
|
+
// React Router v6: path="/*" does NOT work for root — must use path="*"
|
|
93
|
+
const routePath = prefix === '/' ? '*' : `${prefix}/*`
|
|
88
94
|
|
|
89
95
|
if (app.renderer === 'custom') {
|
|
90
96
|
return (
|
|
91
97
|
<Route
|
|
92
98
|
key={app.slug}
|
|
93
|
-
path={
|
|
99
|
+
path={routePath}
|
|
94
100
|
element={
|
|
95
101
|
<AppWrapper app={app}>
|
|
96
102
|
<CustomAppLoader slug={app.slug} />
|
|
@@ -104,7 +110,7 @@ function AuthenticatedRouter() {
|
|
|
104
110
|
return (
|
|
105
111
|
<Route
|
|
106
112
|
key={app.slug}
|
|
107
|
-
path={
|
|
113
|
+
path={routePath}
|
|
108
114
|
element={
|
|
109
115
|
<AppWrapper app={app}>
|
|
110
116
|
<GenericAppShell app={app} />
|
|
@@ -117,7 +123,8 @@ function AuthenticatedRouter() {
|
|
|
117
123
|
return null
|
|
118
124
|
})}
|
|
119
125
|
|
|
120
|
-
|
|
126
|
+
{/* 404 — suppressed when a root app is installed (it handles its own not-found) */}
|
|
127
|
+
{!hasRootApp && <Route path="*" element={<NotFoundPage />} />}
|
|
121
128
|
</Routes>
|
|
122
129
|
</Suspense>
|
|
123
130
|
)
|
|
@@ -57,7 +57,7 @@ class AppErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState>
|
|
|
57
57
|
// Static glob maps — Vite analyzes these at build time and builds a complete
|
|
58
58
|
// module map. Runtime lookup is just a map key lookup, no dynamic string eval.
|
|
59
59
|
// Custom apps take precedence over core apps with the same slug.
|
|
60
|
-
const customAppModules = import.meta.glob('
|
|
60
|
+
const customAppModules = import.meta.glob('../../custom/apps/*/index.tsx')
|
|
61
61
|
const coreAppModules = import.meta.glob('../apps/*/index.tsx')
|
|
62
62
|
|
|
63
63
|
// Module-level cache for lazy components to avoid re-creating on each render
|
|
@@ -66,7 +66,7 @@ const appModuleCache = new Map<string, React.LazyExoticComponent<React.Component
|
|
|
66
66
|
// Resolve the glob key for a given slug from the custom or core map.
|
|
67
67
|
function resolveAppLoader(slug: string): (() => Promise<{ default: React.ComponentType }>) | null {
|
|
68
68
|
// Check custom first (custom/apps/{slug}/index.tsx)
|
|
69
|
-
const customKey =
|
|
69
|
+
const customKey = `../../custom/apps/${slug}/index.tsx`
|
|
70
70
|
if (customAppModules[customKey]) {
|
|
71
71
|
return customAppModules[customKey] as () => Promise<{ default: React.ComponentType }>
|
|
72
72
|
}
|
package/LICENSE.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Spine Framework Internal Use License 1.0.0
|
|
2
|
+
|
|
3
|
+
**Source-available. Free for internal use. Commercial rights reserved.**
|
|
4
|
+
|
|
5
|
+
Copyright © 2026 Dahl Ventures Inc. All rights reserved.
|
|
6
|
+
|
|
7
|
+
This license is based on the PolyForm Internal Use License 1.0.0, modified for Spine Framework.
|
|
8
|
+
|
|
9
|
+
## Quick Summary
|
|
10
|
+
|
|
11
|
+
**You CAN:** Use Spine Framework inside your company for internal business operations.
|
|
12
|
+
**You CANNOT:** Sell it, offer it as SaaS, white-label it, distribute it, or use it to build competing products without a Commercial License.
|
|
13
|
+
|
|
14
|
+
## Full Terms
|
|
15
|
+
|
|
16
|
+
See the complete license text at: https://spine-framework.com/license
|
|
17
|
+
|
|
18
|
+
For Commercial Licensing inquiries: webmaster@spine-framework.com
|
package/config/vite.config.ts
CHANGED
|
@@ -21,7 +21,6 @@ export default defineConfig({
|
|
|
21
21
|
'vendor-react': ['react', 'react-dom', 'react-router-dom'],
|
|
22
22
|
'vendor-supabase': ['@supabase/supabase-js'],
|
|
23
23
|
'vendor-ui': ['lucide-react', 'clsx', 'tailwind-merge', 'class-variance-authority'],
|
|
24
|
-
'vendor-markdown': ['marked'],
|
|
25
24
|
},
|
|
26
25
|
},
|
|
27
26
|
},
|
package/package-project.json
CHANGED
|
@@ -5,12 +5,17 @@
|
|
|
5
5
|
"scripts": {
|
|
6
6
|
"assemble": "bash node_modules/spine-framework/scripts/assemble.sh",
|
|
7
7
|
"dev": "netlify dev",
|
|
8
|
-
"build": "npm run assemble &&
|
|
8
|
+
"build": "npm run assemble && vite build --config node_modules/spine-framework/config/vite.config.ts",
|
|
9
9
|
"preview": "netlify dev"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"spine-framework": "^0.
|
|
12
|
+
"spine-framework": "^0.2.0",
|
|
13
13
|
"@tanstack/react-query": "^5.0.0",
|
|
14
|
+
"react": "^18.3.0",
|
|
15
|
+
"react-dom": "^18.3.0",
|
|
16
|
+
"react-router-dom": "^6.28.0",
|
|
17
|
+
"@netlify/functions": "^2.0.0",
|
|
18
|
+
"react-is": "^18.3.0",
|
|
14
19
|
"lucide-react": "^0.400.0",
|
|
15
20
|
"clsx": "^2.0.0",
|
|
16
21
|
"tailwind-merge": "^2.0.0",
|
|
@@ -54,6 +59,8 @@
|
|
|
54
59
|
"highlight.js": "^11.11.1"
|
|
55
60
|
},
|
|
56
61
|
"devDependencies": {
|
|
62
|
+
"@types/react": "^18.3.0",
|
|
63
|
+
"@types/react-dom": "^18.3.0",
|
|
57
64
|
"vite": "^6.4.3",
|
|
58
65
|
"@vitejs/plugin-react": "^4.0.0",
|
|
59
66
|
"tailwindcss": "^3.4.0",
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spine-framework",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Spine — enterprise application framework built on Supabase + Netlify + React",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"license": "
|
|
7
|
+
"license": "SEE LICENSE IN LICENSE.md",
|
|
8
8
|
"keywords": [
|
|
9
9
|
"spine",
|
|
10
10
|
"framework",
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
"enterprise",
|
|
15
15
|
"agentic"
|
|
16
16
|
],
|
|
17
|
-
"homepage": "https://github.com/
|
|
17
|
+
"homepage": "https://github.com/spine-framework/spine-framework#readme",
|
|
18
18
|
"bugs": {
|
|
19
|
-
"url": "https://github.com/
|
|
19
|
+
"url": "https://github.com/spine-framework/spine-framework/issues"
|
|
20
20
|
},
|
|
21
21
|
"repository": {
|
|
22
22
|
"type": "git",
|
|
23
|
-
"url": "https://github.com/
|
|
23
|
+
"url": "https://github.com/spine-framework/spine-framework"
|
|
24
24
|
},
|
|
25
25
|
"engines": {
|
|
26
26
|
"node": ">=18.0.0"
|
|
@@ -61,7 +61,8 @@
|
|
|
61
61
|
"index.html",
|
|
62
62
|
"package-project.json",
|
|
63
63
|
"STRUCTURE.md",
|
|
64
|
-
"README.md"
|
|
64
|
+
"README.md",
|
|
65
|
+
"LICENSE.md"
|
|
65
66
|
],
|
|
66
67
|
"scripts": {
|
|
67
68
|
"spine-framework": "tsx .framework/cli/index.ts",
|
|
@@ -61,14 +61,11 @@ if [ -f "$PROJECT_ROOT/.framework/public/_redirects" ]; then
|
|
|
61
61
|
echo " ✓ Core: _redirects copied to Vite-served directory for Netlify dev"
|
|
62
62
|
fi
|
|
63
63
|
|
|
64
|
-
# 6.
|
|
64
|
+
# 6. Copy custom/apps/ → .assembled/custom/apps/ (preserves path for CustomAppLoader glob)
|
|
65
|
+
ASSEMBLED_CUSTOM_DIR="$PROJECT_ROOT/.assembled/custom/apps"
|
|
65
66
|
if [ -d "$CUSTOM_SRC_DIR" ]; then
|
|
66
|
-
|
|
67
|
-
cp -r "$CUSTOM_SRC_DIR"/* "$
|
|
68
|
-
|
|
69
|
-
# Handle subdirectories properly
|
|
70
|
-
find "$CUSTOM_SRC_DIR" -mindepth 1 -type d -exec sh -c 'dir="$1"; base=$(basename "$dir"); mkdir -p "'"$TARGET_SRC_DIR"'/$base" && cp -r "$dir"/* "'"$TARGET_SRC_DIR"'/$base/"' _ {} \; 2>/dev/null || true
|
|
71
|
-
|
|
67
|
+
mkdir -p "$ASSEMBLED_CUSTOM_DIR"
|
|
68
|
+
cp -r "$CUSTOM_SRC_DIR"/* "$ASSEMBLED_CUSTOM_DIR"/ 2>/dev/null || true
|
|
72
69
|
CUSTOM_COUNT=$(find "$CUSTOM_SRC_DIR" -name '*.tsx' -o -name '*.ts' -o -name '*.css' 2>/dev/null | wc -l | tr -d ' ')
|
|
73
70
|
echo " ✓ Custom: $CUSTOM_COUNT files"
|
|
74
71
|
else
|