fix(plugins): respect USE_FRONTEND_BACKUP and create plugins dir
Resolve plugin directory based on USE_FRONTEND_BACKUP so /api/plugins works with both frontend-backup and built frontend, aligning with index.ts. Ensure /app/frontend/plugins is created during non-backup Docker builds to avoid missing-directory issues at runtime. Update backup asset import reference and adjust local helper script path.
This commit is contained in:
+4
-2
@@ -30,7 +30,9 @@ ARG USE_FRONTEND_BACKUP
|
|||||||
RUN if [ "$USE_FRONTEND_BACKUP" = "true" ]; then \
|
RUN if [ "$USE_FRONTEND_BACKUP" = "true" ]; then \
|
||||||
rm -rf /app/frontend && mkdir -p /app/frontend && cp -R /app/frontend-backup/. /app/frontend/; \
|
rm -rf /app/frontend && mkdir -p /app/frontend && cp -R /app/frontend-backup/. /app/frontend/; \
|
||||||
else \
|
else \
|
||||||
cd frontend-src && npm install && npm run build; \
|
cd frontend-src && npm install && npm run build && \
|
||||||
|
mkdir -p /app/frontend/plugins && \
|
||||||
|
echo "Plugins directory created for frontend build"; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create login.html from join.html if it doesn't exist
|
# Create login.html from join.html if it doesn't exist
|
||||||
@@ -65,7 +67,7 @@ RUN pnpm db:generate
|
|||||||
# Copy built application from builder stage
|
# Copy built application from builder stage
|
||||||
COPY --from=builder /app/dist ./dist
|
COPY --from=builder /app/dist ./dist
|
||||||
|
|
||||||
# Copy built frontend from builder stage
|
# Copy built frontend from builder stage (includes SDK and plugins directory)
|
||||||
COPY --from=builder /app/frontend ./frontend
|
COPY --from=builder /app/frontend ./frontend
|
||||||
|
|
||||||
# Expose port
|
# Expose port
|
||||||
|
|||||||
+125
@@ -0,0 +1,125 @@
|
|||||||
|
# FurryPlace Plugins System
|
||||||
|
|
||||||
|
The FurryPlace SDK provides an extensible plugin system that allows you to add custom buttons and functionality to the UI without modifying the core codebase.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Development (Local)
|
||||||
|
|
||||||
|
1. Add your plugin file to `frontend-backup/plugins/`:
|
||||||
|
```bash
|
||||||
|
# Example: Create a custom button plugin
|
||||||
|
cat > frontend-backup/plugins/my-plugin.js << 'EOF'
|
||||||
|
(function() {
|
||||||
|
function waitForSDK(callback) {
|
||||||
|
if (window.FurryPlaceSDK) {
|
||||||
|
callback();
|
||||||
|
} else {
|
||||||
|
setTimeout(() => waitForSDK(callback), 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForSDK(() => {
|
||||||
|
window.FurryPlaceSDK.registerButton({
|
||||||
|
id: 'my-button',
|
||||||
|
title: 'My Custom Button',
|
||||||
|
position: 'bottom',
|
||||||
|
icon: '<svg>...</svg>',
|
||||||
|
onClick: () => alert('Clicked!')
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Refresh your browser - the plugin loads automatically!
|
||||||
|
|
||||||
|
### Production (Docker)
|
||||||
|
|
||||||
|
When using `USE_FRONTEND_BACKUP=true`:
|
||||||
|
|
||||||
|
1. **Before building the Docker image**, add plugins to `frontend-backup/plugins/`
|
||||||
|
2. Build the image:
|
||||||
|
```bash
|
||||||
|
docker build --build-arg USE_FRONTEND_BACKUP=true -t furryplace .
|
||||||
|
```
|
||||||
|
3. The plugins will be included in the image automatically
|
||||||
|
|
||||||
|
When using the regular frontend build (not `USE_FRONTEND_BACKUP`):
|
||||||
|
|
||||||
|
1. Create a `frontend-src/public/plugins/` directory
|
||||||
|
2. Add your plugin files there
|
||||||
|
3. Build normally - the plugins will be copied to the final build
|
||||||
|
|
||||||
|
### Runtime Plugin Loading (Docker Volume)
|
||||||
|
|
||||||
|
You can also mount a plugins directory at runtime to add/update plugins without rebuilding:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
-v ./my-plugins:/app/frontend/plugins \
|
||||||
|
-e USE_FRONTEND_BACKUP=false \
|
||||||
|
furryplace
|
||||||
|
```
|
||||||
|
|
||||||
|
Or with docker-compose:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
furryplace:
|
||||||
|
image: furryplace
|
||||||
|
volumes:
|
||||||
|
- ./my-plugins:/app/frontend/plugins
|
||||||
|
environment:
|
||||||
|
USE_FRONTEND_BACKUP: "false"
|
||||||
|
```
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
1. **Backend**: The `/api/plugins` endpoint (in `src/routes/plugins.ts`) scans the plugins directory and returns a list of `.js` files
|
||||||
|
2. **Frontend**: The SDK (`furryplace-sdk.js`) automatically fetches this list and dynamically loads each plugin
|
||||||
|
3. **Plugins**: Each plugin registers buttons or functionality using the SDK API
|
||||||
|
|
||||||
|
## Plugin Development
|
||||||
|
|
||||||
|
See the full documentation in [frontend-backup/plugins/README.md](frontend-backup/plugins/README.md) for:
|
||||||
|
- SDK API reference
|
||||||
|
- Button configuration options
|
||||||
|
- Example plugins
|
||||||
|
- Troubleshooting tips
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
The plugin system respects the `USE_FRONTEND_BACKUP` environment variable:
|
||||||
|
- `USE_FRONTEND_BACKUP=true` → Loads from `frontend-backup/plugins/`
|
||||||
|
- `USE_FRONTEND_BACKUP=false` → Loads from `frontend/plugins/`
|
||||||
|
|
||||||
|
This is automatically handled by the backend routes.
|
||||||
|
|
||||||
|
## Disabling Plugins
|
||||||
|
|
||||||
|
To disable a plugin without deleting it:
|
||||||
|
1. Rename it to anything that doesn't end in `.js` (e.g., `my-plugin.js.disabled`)
|
||||||
|
2. Refresh the page
|
||||||
|
|
||||||
|
The SDK only loads files ending in `.js`.
|
||||||
|
|
||||||
|
## Security Notes
|
||||||
|
|
||||||
|
- Plugins have full access to the browser's JavaScript environment
|
||||||
|
- Only load plugins from trusted sources
|
||||||
|
- Consider reviewing plugin code before deployment
|
||||||
|
- Plugins run in the same origin as your application
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
Example plugins are included in `frontend-backup/plugins/example-button.js`:
|
||||||
|
- Help button with tooltip
|
||||||
|
- Debug info button
|
||||||
|
- Conditional rendering example
|
||||||
|
- External link button (Discord)
|
||||||
|
|
||||||
|
To try them out:
|
||||||
|
1. The example plugin is automatically loaded
|
||||||
|
2. Check the browser console for loading messages
|
||||||
|
3. Look for the new buttons in the UI
|
||||||
@@ -29,7 +29,7 @@ const __vite__mapDeps = (
|
|||||||
"../chunks/D3yDgRbd.js",
|
"../chunks/D3yDgRbd.js",
|
||||||
"../chunks/wZ7b5CwQ.js",
|
"../chunks/wZ7b5CwQ.js",
|
||||||
"../nodes/3.DOMAwJeg.js",
|
"../nodes/3.DOMAwJeg.js",
|
||||||
"../nodes/4.DB4WphWP.js",
|
"../nodes/4.CrDfIbdR.js",
|
||||||
"../chunks/DueIxFLX.js",
|
"../chunks/DueIxFLX.js",
|
||||||
"../chunks/CgCA7Awo.js",
|
"../chunks/CgCA7Awo.js",
|
||||||
"../chunks/Dpga8uG-.js",
|
"../chunks/Dpga8uG-.js",
|
||||||
@@ -6133,7 +6133,7 @@ const Ll = ai(gl),
|
|||||||
),
|
),
|
||||||
() =>
|
() =>
|
||||||
L(
|
L(
|
||||||
() => import("../nodes/4.DB4WphWP.js"),
|
() => import("../nodes/4.CrDfIbdR.js"),
|
||||||
__vite__mapDeps([
|
__vite__mapDeps([
|
||||||
26, 1, 2, 3, 4, 5, 10, 12, 22, 11, 20, 19, 6, 7, 8, 9, 27, 13, 28, 29,
|
26, 1, 2, 3, 4, 5, 10, 12, 22, 11, 20, 19, 6, 7, 8, 9, 27, 13, 28, 29,
|
||||||
30, 31, 32, 33, 34, 24, 35, 36, 37, 38, 39, 40, 15, 18, 23, 14, 41,
|
30, 31, 32, 33, 34, 24, 35, 36, 37, 38, 39, 40, 15, 18, 23, 14, 41,
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Ignore all plugin files except the example
|
||||||
|
*
|
||||||
|
!.gitignore
|
||||||
|
!README.md
|
||||||
|
!example-button.js
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const filePath = 'f:\\place\\openplace\\frontend-backup\\_app\\immutable\\nodes\\4.CrDfIbdR.js';
|
const filePath = 'f:\\place\\FurryPlace\\frontend-backup\\_app\\immutable\\nodes\\4.CrDfIbdR.js';
|
||||||
|
|
||||||
// Read the file
|
// Read the file
|
||||||
let content = fs.readFileSync(filePath, 'utf8');
|
let content = fs.readFileSync(filePath, 'utf8');
|
||||||
|
|||||||
@@ -6,11 +6,14 @@ import { fileURLToPath } from 'url';
|
|||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
|
// Determine which frontend directory to use (matches index.ts logic)
|
||||||
|
const frontendDir = process.env['USE_FRONTEND_BACKUP'] === 'true' ? 'frontend-backup' : 'frontend';
|
||||||
|
|
||||||
export function setupPluginRoutes(app: App) {
|
export function setupPluginRoutes(app: App) {
|
||||||
// Public endpoint - Get list of available plugins
|
// Public endpoint - Get list of available plugins
|
||||||
app.get('/api/plugins', async (_req, res) => {
|
app.get('/api/plugins', async (_req, res) => {
|
||||||
try {
|
try {
|
||||||
const pluginsDir = path.join(__dirname, '..', '..', 'frontend-backup', 'plugins');
|
const pluginsDir = path.join(__dirname, '..', '..', frontendDir, 'plugins');
|
||||||
|
|
||||||
// Check if plugins directory exists
|
// Check if plugins directory exists
|
||||||
if (!fs.existsSync(pluginsDir)) {
|
if (!fs.existsSync(pluginsDir)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user