feat: externalize buttplug as separate nginx container
- Add Dockerfile.buttplug: builds Rust/WASM + TS, serves via nginx - Add nginx.buttplug.conf: serves /dist and /wasm with correct MIME types - Add .gitea/workflows/docker-build-buttplug.yml: path-filtered CI workflow - Strip Rust toolchain and buttplug build from frontend Dockerfile - Move buttplug to devDependencies (types only at build time) - Remove vite-plugin-wasm from frontend (WASM now served by nginx) - Add /buttplug proxy in vite.config (dev: localhost:8080) - Add buttplug service to compose.yml - Load buttplug dynamically in play page via runtime import - Fix faq page: suppress no-unnecessary-state-wrap for reassigned SvelteSet Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
68
.gitea/workflows/docker-build-buttplug.yml
Normal file
68
.gitea/workflows/docker-build-buttplug.yml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
name: Build and Push Buttplug Image
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- develop
|
||||||
|
tags:
|
||||||
|
- "v*.*.*"
|
||||||
|
paths:
|
||||||
|
- "packages/buttplug/**"
|
||||||
|
- "Dockerfile.buttplug"
|
||||||
|
- "nginx.buttplug.conf"
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "packages/buttplug/**"
|
||||||
|
- "Dockerfile.buttplug"
|
||||||
|
- "nginx.buttplug.conf"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: dev.pivoine.art
|
||||||
|
IMAGE_NAME: valknar/sexy-buttplug
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
with:
|
||||||
|
platforms: linux/amd64
|
||||||
|
|
||||||
|
- name: Log in to Gitea Container Registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ gitea.actor }}
|
||||||
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
|
||||||
|
- name: Extract metadata
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v5
|
||||||
|
with:
|
||||||
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
|
tags: |
|
||||||
|
type=raw,value=latest,enable={{is_default_branch}}
|
||||||
|
type=ref,event=branch
|
||||||
|
type=ref,event=pr
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=sha,prefix={{branch}}-
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: Dockerfile.buttplug
|
||||||
|
platforms: linux/amd64
|
||||||
|
push: ${{ gitea.event_name != 'pull_request' }}
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache
|
||||||
|
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
|
||||||
42
Dockerfile
42
Dockerfile
@@ -20,48 +20,19 @@ RUN mkdir -p ./packages/frontend && \
|
|||||||
printf 'PUBLIC_API_URL=\nPUBLIC_URL=\nPUBLIC_UMAMI_ID=\nPUBLIC_UMAMI_SCRIPT=\n' > ./packages/frontend/.env
|
printf 'PUBLIC_API_URL=\nPUBLIC_URL=\nPUBLIC_UMAMI_ID=\nPUBLIC_UMAMI_SCRIPT=\n' > ./packages/frontend/.env
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Builder stage - compile application with Rust/WASM support
|
# Builder stage - compile frontend
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
FROM base AS builder
|
FROM base AS builder
|
||||||
ARG CI=false
|
ARG CI=false
|
||||||
ENV CI=$CI
|
ENV CI=$CI
|
||||||
|
|
||||||
# Install build dependencies for Rust and native modules
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
curl \
|
|
||||||
build-essential \
|
|
||||||
pkg-config \
|
|
||||||
libssl-dev \
|
|
||||||
ca-certificates \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Install Rust toolchain
|
|
||||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \
|
|
||||||
--default-toolchain stable \
|
|
||||||
--profile minimal \
|
|
||||||
--target wasm32-unknown-unknown
|
|
||||||
|
|
||||||
# Add Rust to PATH
|
|
||||||
ENV PATH="/root/.cargo/bin:${PATH}"
|
|
||||||
|
|
||||||
# Install wasm-bindgen-cli
|
|
||||||
RUN cargo install wasm-bindgen-cli
|
|
||||||
|
|
||||||
# Copy source files
|
# Copy source files
|
||||||
COPY packages ./packages
|
COPY packages ./packages
|
||||||
|
|
||||||
# Install all dependencies
|
# Install all dependencies
|
||||||
RUN pnpm install --frozen-lockfile
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
# Build packages in correct order with WASM support
|
# Build frontend
|
||||||
# 1. Build buttplug WASM
|
|
||||||
RUN RUSTFLAGS='--cfg getrandom_backend="wasm_js" --cfg=web_sys_unstable_apis' \
|
|
||||||
pnpm --filter @sexy.pivoine.art/buttplug build:wasm
|
|
||||||
|
|
||||||
# 2. Build buttplug TypeScript
|
|
||||||
RUN pnpm --filter @sexy.pivoine.art/buttplug build
|
|
||||||
|
|
||||||
# 3. Build frontend
|
|
||||||
RUN pnpm --filter @sexy.pivoine.art/frontend build
|
RUN pnpm --filter @sexy.pivoine.art/frontend build
|
||||||
|
|
||||||
# Prune dev dependencies for production
|
# Prune dev dependencies for production
|
||||||
@@ -91,19 +62,14 @@ COPY --from=builder --chown=node:node /app/package.json ./package.json
|
|||||||
COPY --from=builder --chown=node:node /app/pnpm-lock.yaml ./pnpm-lock.yaml
|
COPY --from=builder --chown=node:node /app/pnpm-lock.yaml ./pnpm-lock.yaml
|
||||||
COPY --from=builder --chown=node:node /app/pnpm-workspace.yaml ./pnpm-workspace.yaml
|
COPY --from=builder --chown=node:node /app/pnpm-workspace.yaml ./pnpm-workspace.yaml
|
||||||
|
|
||||||
# Create package directories
|
# Create package directory
|
||||||
RUN mkdir -p packages/frontend packages/buttplug
|
RUN mkdir -p packages/frontend
|
||||||
|
|
||||||
# Copy frontend artifacts
|
# Copy frontend artifacts
|
||||||
COPY --from=builder --chown=node:node /app/packages/frontend/build ./packages/frontend/build
|
COPY --from=builder --chown=node:node /app/packages/frontend/build ./packages/frontend/build
|
||||||
COPY --from=builder --chown=node:node /app/packages/frontend/node_modules ./packages/frontend/node_modules
|
COPY --from=builder --chown=node:node /app/packages/frontend/node_modules ./packages/frontend/node_modules
|
||||||
COPY --from=builder --chown=node:node /app/packages/frontend/package.json ./packages/frontend/package.json
|
COPY --from=builder --chown=node:node /app/packages/frontend/package.json ./packages/frontend/package.json
|
||||||
|
|
||||||
# Copy buttplug artifacts
|
|
||||||
COPY --from=builder --chown=node:node /app/packages/buttplug/dist ./packages/buttplug/dist
|
|
||||||
COPY --from=builder --chown=node:node /app/packages/buttplug/node_modules ./packages/buttplug/node_modules
|
|
||||||
COPY --from=builder --chown=node:node /app/packages/buttplug/package.json ./packages/buttplug/package.json
|
|
||||||
|
|
||||||
# Switch to non-root user
|
# Switch to non-root user
|
||||||
USER node
|
USER node
|
||||||
|
|
||||||
|
|||||||
65
Dockerfile.buttplug
Normal file
65
Dockerfile.buttplug
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Builder stage - compile Rust/WASM and TypeScript
|
||||||
|
# ============================================================================
|
||||||
|
FROM node:22.11.0-slim AS builder
|
||||||
|
|
||||||
|
# Install build dependencies for Rust
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
curl \
|
||||||
|
build-essential \
|
||||||
|
pkg-config \
|
||||||
|
libssl-dev \
|
||||||
|
ca-certificates \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Enable corepack for pnpm
|
||||||
|
RUN npm install -g corepack@latest && corepack enable
|
||||||
|
|
||||||
|
# Install Rust toolchain
|
||||||
|
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \
|
||||||
|
--default-toolchain stable \
|
||||||
|
--profile minimal \
|
||||||
|
--target wasm32-unknown-unknown
|
||||||
|
|
||||||
|
ENV PATH="/root/.cargo/bin:${PATH}"
|
||||||
|
|
||||||
|
# Install wasm-bindgen-cli
|
||||||
|
RUN cargo install wasm-bindgen-cli
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy workspace configuration
|
||||||
|
COPY pnpm-workspace.yaml package.json pnpm-lock.yaml ./
|
||||||
|
COPY packages/buttplug ./packages/buttplug
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN pnpm install --frozen-lockfile --filter @sexy.pivoine.art/buttplug
|
||||||
|
|
||||||
|
# Build WASM
|
||||||
|
RUN RUSTFLAGS='--cfg getrandom_backend="wasm_js" --cfg=web_sys_unstable_apis' \
|
||||||
|
pnpm --filter @sexy.pivoine.art/buttplug build:wasm
|
||||||
|
|
||||||
|
# Build TypeScript
|
||||||
|
RUN pnpm --filter @sexy.pivoine.art/buttplug build
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Runner stage - nginx serving dist/ and wasm/
|
||||||
|
# ============================================================================
|
||||||
|
FROM nginx:1.27-alpine AS runner
|
||||||
|
|
||||||
|
# Remove default nginx config
|
||||||
|
RUN rm /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
# Copy nginx config
|
||||||
|
COPY nginx.buttplug.conf /etc/nginx/conf.d/buttplug.conf
|
||||||
|
|
||||||
|
# Copy built artifacts
|
||||||
|
COPY --from=builder /app/packages/buttplug/dist /usr/share/nginx/html/dist
|
||||||
|
COPY --from=builder /app/packages/buttplug/wasm /usr/share/nginx/html/wasm
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
|
||||||
|
CMD wget --no-verbose --tries=1 --spider http://localhost/dist/index.js || exit 1
|
||||||
18
compose.yml
18
compose.yml
@@ -64,6 +64,21 @@ services:
|
|||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 3
|
retries: 3
|
||||||
start_period: 20s
|
start_period: 20s
|
||||||
|
buttplug:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.buttplug
|
||||||
|
container_name: sexy_buttplug
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "8080:80"
|
||||||
|
healthcheck:
|
||||||
|
test:
|
||||||
|
["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost/dist/index.js"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
start_period: 10s
|
||||||
frontend:
|
frontend:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
@@ -78,9 +93,12 @@ services:
|
|||||||
HOST: 0.0.0.0
|
HOST: 0.0.0.0
|
||||||
PUBLIC_API_URL: http://sexy_backend:4000
|
PUBLIC_API_URL: http://sexy_backend:4000
|
||||||
PUBLIC_URL: http://localhost:3000
|
PUBLIC_URL: http://localhost:3000
|
||||||
|
BUTTPLUG_URL: http://sexy_buttplug:80
|
||||||
depends_on:
|
depends_on:
|
||||||
backend:
|
backend:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
buttplug:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
uploads_data:
|
uploads_data:
|
||||||
|
|||||||
23
nginx.buttplug.conf
Normal file
23
nginx.buttplug.conf
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
|
||||||
|
# WASM MIME type
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
types {
|
||||||
|
application/wasm wasm;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cache JS and WASM aggressively (content-addressed by build)
|
||||||
|
location ~* \.(js|wasm)$ {
|
||||||
|
add_header Cache-Control "public, max-age=31536000, immutable";
|
||||||
|
add_header Cross-Origin-Resource-Policy "cross-origin";
|
||||||
|
add_header Cross-Origin-Embedder-Policy "require-corp";
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri =404;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
"check": "svelte-check --tsconfig ./tsconfig.json --threshold warning"
|
"check": "svelte-check --tsconfig ./tsconfig.json --threshold warning"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@sexy.pivoine.art/buttplug": "workspace:*",
|
||||||
"@iconify-json/ri": "^1.2.10",
|
"@iconify-json/ri": "^1.2.10",
|
||||||
"@iconify/tailwind4": "^1.2.1",
|
"@iconify/tailwind4": "^1.2.1",
|
||||||
"@internationalized/date": "^3.11.0",
|
"@internationalized/date": "^3.11.0",
|
||||||
@@ -42,7 +43,6 @@
|
|||||||
"vite-plugin-wasm": "3.5.0"
|
"vite-plugin-wasm": "3.5.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sexy.pivoine.art/buttplug": "workspace:*",
|
|
||||||
"@sexy.pivoine.art/types": "workspace:*",
|
"@sexy.pivoine.art/types": "workspace:*",
|
||||||
"graphql": "^16.11.0",
|
"graphql": "^16.11.0",
|
||||||
"graphql-request": "^7.1.2",
|
"graphql-request": "^7.1.2",
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
import Meta from "$lib/components/meta/meta.svelte";
|
import Meta from "$lib/components/meta/meta.svelte";
|
||||||
|
|
||||||
let searchQuery = $state("");
|
let searchQuery = $state("");
|
||||||
let expandedItems = new SvelteSet<number>();
|
// eslint-disable-next-line svelte/no-unnecessary-state-wrap -- variable is reassigned, $state is required
|
||||||
|
let expandedItems = $state(new SvelteSet<number>());
|
||||||
|
|
||||||
const faqCategories = [
|
const faqCategories = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,14 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { _ } from "svelte-i18n";
|
import { _ } from "svelte-i18n";
|
||||||
import Meta from "$lib/components/meta/meta.svelte";
|
import Meta from "$lib/components/meta/meta.svelte";
|
||||||
import {
|
import type * as ButtplugTypes from "@sexy.pivoine.art/buttplug";
|
||||||
ButtplugClient,
|
|
||||||
ButtplugWasmClientConnector,
|
|
||||||
type ButtplugClientDevice,
|
|
||||||
type OutputType,
|
|
||||||
InputType,
|
|
||||||
DeviceOutputValueConstructor,
|
|
||||||
} from "@sexy.pivoine.art/buttplug";
|
|
||||||
import Button from "$lib/components/ui/button/button.svelte";
|
import Button from "$lib/components/ui/button/button.svelte";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { goto } from "$app/navigation";
|
import { goto } from "$app/navigation";
|
||||||
@@ -19,8 +12,13 @@
|
|||||||
import { toast } from "svelte-sonner";
|
import { toast } from "svelte-sonner";
|
||||||
import SexyBackground from "$lib/components/background/background.svelte";
|
import SexyBackground from "$lib/components/background/background.svelte";
|
||||||
|
|
||||||
const client = new ButtplugClient("Sexy.Art");
|
// Runtime buttplug values — loaded dynamically from the buttplug nginx container
|
||||||
let connected = $state(client.connected);
|
let client: ButtplugTypes.ButtplugClient;
|
||||||
|
let InputType: typeof ButtplugTypes.InputType;
|
||||||
|
let DeviceOutputValueConstructor: typeof ButtplugTypes.DeviceOutputValueConstructor;
|
||||||
|
let ButtplugWasmClientConnector: typeof ButtplugTypes.ButtplugWasmClientConnector;
|
||||||
|
|
||||||
|
let connected = $state(false);
|
||||||
let scanning = $state(false);
|
let scanning = $state(false);
|
||||||
let devices = $state<BluetoothDevice[]>([]);
|
let devices = $state<BluetoothDevice[]>([]);
|
||||||
|
|
||||||
@@ -45,7 +43,7 @@
|
|||||||
// await ButtplugWasmClientConnector.activateLogging("info");
|
// await ButtplugWasmClientConnector.activateLogging("info");
|
||||||
await client.connect(connector);
|
await client.connect(connector);
|
||||||
client.on("deviceadded", onDeviceAdded);
|
client.on("deviceadded", onDeviceAdded);
|
||||||
client.on("deviceremoved", (dev: ButtplugClientDevice) => {
|
client.on("deviceremoved", (dev: ButtplugTypes.ButtplugClientDevice) => {
|
||||||
const idx = devices.findIndex((d) => d.info.index === dev.index);
|
const idx = devices.findIndex((d) => d.info.index === dev.index);
|
||||||
if (idx !== -1) devices.splice(idx, 1);
|
if (idx !== -1) devices.splice(idx, 1);
|
||||||
});
|
});
|
||||||
@@ -59,7 +57,7 @@
|
|||||||
scanning = true;
|
scanning = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onDeviceAdded(dev: ButtplugClientDevice) {
|
async function onDeviceAdded(dev: ButtplugTypes.ButtplugClientDevice) {
|
||||||
const device = convertDevice(dev);
|
const device = convertDevice(dev);
|
||||||
devices.push(device);
|
devices.push(device);
|
||||||
|
|
||||||
@@ -93,7 +91,7 @@
|
|||||||
if (!feature) return;
|
if (!feature) return;
|
||||||
|
|
||||||
actuator.value = value;
|
actuator.value = value;
|
||||||
const outputType = actuator.outputType as typeof OutputType;
|
const outputType = actuator.outputType as typeof ButtplugTypes.OutputType;
|
||||||
await feature.runOutput(new DeviceOutputValueConstructor(outputType).steps(value));
|
await feature.runOutput(new DeviceOutputValueConstructor(outputType).steps(value));
|
||||||
|
|
||||||
// Capture event if recording
|
// Capture event if recording
|
||||||
@@ -141,7 +139,7 @@
|
|||||||
device.actuators.forEach((a) => (a.value = 0));
|
device.actuators.forEach((a) => (a.value = 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertDevice(device: ButtplugClientDevice): BluetoothDevice {
|
function convertDevice(device: ButtplugTypes.ButtplugClientDevice): BluetoothDevice {
|
||||||
const actuators: import("$lib/types").DeviceActuator[] = []; // eslint-disable-line @typescript-eslint/consistent-type-imports
|
const actuators: import("$lib/types").DeviceActuator[] = []; // eslint-disable-line @typescript-eslint/consistent-type-imports
|
||||||
for (const [, feature] of device.features) {
|
for (const [, feature] of device.features) {
|
||||||
for (const outputType of feature.outputTypes) {
|
for (const outputType of feature.outputTypes) {
|
||||||
@@ -333,7 +331,7 @@
|
|||||||
// Send command to device via feature
|
// Send command to device via feature
|
||||||
const feature = device.info.features.get(actuator.featureIndex);
|
const feature = device.info.features.get(actuator.featureIndex);
|
||||||
if (feature) {
|
if (feature) {
|
||||||
const outputType = actuator.outputType as typeof OutputType;
|
const outputType = actuator.outputType as typeof ButtplugTypes.OutputType;
|
||||||
feature.runOutput(new DeviceOutputValueConstructor(outputType).steps(deviceValue));
|
feature.runOutput(new DeviceOutputValueConstructor(outputType).steps(deviceValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,12 +363,20 @@
|
|||||||
|
|
||||||
const { data } = $props();
|
const { data } = $props();
|
||||||
|
|
||||||
onMount(() => {
|
onMount(async () => {
|
||||||
if (data.authStatus.authenticated) {
|
if (!data.authStatus.authenticated) {
|
||||||
init();
|
goto("/login");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
goto("/login");
|
// Concatenation prevents Rollup from statically resolving this URL at build time
|
||||||
|
const buttplugUrl = "/buttplug/" + "dist/index.js";
|
||||||
|
const bp = await import(/* @vite-ignore */ buttplugUrl);
|
||||||
|
InputType = bp.InputType;
|
||||||
|
DeviceOutputValueConstructor = bp.DeviceOutputValueConstructor;
|
||||||
|
ButtplugWasmClientConnector = bp.ButtplugWasmClientConnector;
|
||||||
|
client = new bp.ButtplugClient("Sexy.Art");
|
||||||
|
connected = client.connected;
|
||||||
|
await init();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,17 @@ import path from "path";
|
|||||||
import tailwindcss from "@tailwindcss/vite";
|
import tailwindcss from "@tailwindcss/vite";
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
import { sveltekit } from "@sveltejs/kit/vite";
|
import { sveltekit } from "@sveltejs/kit/vite";
|
||||||
import wasm from "vite-plugin-wasm";
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [sveltekit(), tailwindcss(), wasm()],
|
plugins: [sveltekit(), tailwindcss()],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: { $lib: path.resolve("./src/lib"), "@": path.resolve("./src/lib") },
|
alias: { $lib: path.resolve("./src/lib"), "@": path.resolve("./src/lib") },
|
||||||
},
|
},
|
||||||
|
build: {
|
||||||
|
rollupOptions: {
|
||||||
|
external: ["@sexy.pivoine.art/buttplug"],
|
||||||
|
},
|
||||||
|
},
|
||||||
server: {
|
server: {
|
||||||
port: 3000,
|
port: 3000,
|
||||||
proxy: {
|
proxy: {
|
||||||
@@ -19,6 +23,11 @@ export default defineConfig({
|
|||||||
secure: false,
|
secure: false,
|
||||||
ws: true,
|
ws: true,
|
||||||
},
|
},
|
||||||
|
"/buttplug": {
|
||||||
|
rewrite: (path) => path.replace(/^\/buttplug/, ""),
|
||||||
|
target: "http://localhost:8080",
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
6
pnpm-lock.yaml
generated
6
pnpm-lock.yaml
generated
@@ -151,9 +151,6 @@ importers:
|
|||||||
|
|
||||||
packages/frontend:
|
packages/frontend:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sexy.pivoine.art/buttplug':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../buttplug
|
|
||||||
'@sexy.pivoine.art/types':
|
'@sexy.pivoine.art/types':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../types
|
version: link:../types
|
||||||
@@ -188,6 +185,9 @@ importers:
|
|||||||
'@lucide/svelte':
|
'@lucide/svelte':
|
||||||
specifier: ^0.561.0
|
specifier: ^0.561.0
|
||||||
version: 0.561.0(svelte@5.53.7)
|
version: 0.561.0(svelte@5.53.7)
|
||||||
|
'@sexy.pivoine.art/buttplug':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../buttplug
|
||||||
'@sveltejs/adapter-node':
|
'@sveltejs/adapter-node':
|
||||||
specifier: ^5.5.4
|
specifier: ^5.5.4
|
||||||
version: 5.5.4(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)))
|
version: 5.5.4(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)))
|
||||||
|
|||||||
Reference in New Issue
Block a user