feat: add shared @sexy.pivoine.art/types package and fix type safety across frontend/backend
- Create packages/types with shared TypeScript domain model interfaces (User, Video, Model, Article, Comment, Recording, etc.) - Wire both frontend and backend packages to use @sexy.pivoine.art/types via workspace:* - Update backend Pothos objectRef types to use shared interfaces instead of inline types - Update frontend $lib/types.ts to re-export from shared package - Fix all type errors introduced by more accurate nullable types (avatar/banner as string|null UUIDs, author nullable, events/device_info as object[]) - Add artist_name to comment user select in backend resolver - Widen utility function signatures (getAssetUrl, getUserInitials, calcReadingTime) to accept null/undefined Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import { getRecording } from "$lib/services";
|
||||
import type { Recording } from "$lib/types";
|
||||
|
||||
export async function load({ locals, url, fetch }) {
|
||||
const recordingId = url.searchParams.get("recording");
|
||||
|
||||
let recording = null;
|
||||
let recording: Recording | null = null;
|
||||
if (recordingId && locals.authStatus.authenticated) {
|
||||
try {
|
||||
recording = await getRecording(recordingId, fetch);
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
InputType,
|
||||
DeviceOutputValueConstructor,
|
||||
} from "@sexy.pivoine.art/buttplug";
|
||||
import type { ButtplugMessage } from "@sexy.pivoine.art/buttplug";
|
||||
import Button from "$lib/components/ui/button/button.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
@@ -74,7 +73,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
function handleInputReading(msg: ButtplugMessage) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function handleInputReading(msg: any) {
|
||||
if (msg.InputReading === undefined) return;
|
||||
const reading = msg.InputReading;
|
||||
const device = devices.find((d) => d.info.index === reading.DeviceIndex);
|
||||
@@ -92,7 +92,7 @@
|
||||
if (!feature) return;
|
||||
|
||||
actuator.value = value;
|
||||
const outputType = actuator.outputType as OutputType;
|
||||
const outputType = actuator.outputType as typeof OutputType;
|
||||
await feature.runOutput(new DeviceOutputValueConstructor(outputType).steps(value));
|
||||
|
||||
// Capture event if recording
|
||||
@@ -225,7 +225,7 @@
|
||||
}
|
||||
|
||||
// Check if we need to map devices
|
||||
if (deviceMappings.size === 0 && data.recording.device_info.length > 0) {
|
||||
if (deviceMappings.size === 0 && (data.recording.device_info?.length ?? 0) > 0) {
|
||||
showMappingDialog = true;
|
||||
return;
|
||||
}
|
||||
@@ -284,7 +284,7 @@
|
||||
function scheduleNextEvent() {
|
||||
if (!data.recording || !isPlaying || !playbackStartTime) return;
|
||||
|
||||
const events = data.recording.events;
|
||||
const events = (data.recording.events ?? []) as RecordedEvent[];
|
||||
if (currentEventIndex >= events.length) {
|
||||
stopPlayback();
|
||||
toast.success("Playback finished");
|
||||
@@ -332,7 +332,7 @@
|
||||
// Send command to device via feature
|
||||
const feature = device.info.features.get(actuator.featureIndex);
|
||||
if (feature) {
|
||||
const outputType = actuator.outputType as OutputType;
|
||||
const outputType = actuator.outputType as typeof OutputType;
|
||||
feature.runOutput(new DeviceOutputValueConstructor(outputType).steps(deviceValue));
|
||||
}
|
||||
|
||||
@@ -347,9 +347,10 @@
|
||||
playbackProgress = targetTime;
|
||||
|
||||
// Find the event index at this time
|
||||
currentEventIndex = data.recording.events.findIndex((e) => e.timestamp >= targetTime);
|
||||
const seekEvents = (data.recording.events ?? []) as RecordedEvent[];
|
||||
currentEventIndex = seekEvents.findIndex((e) => e.timestamp >= targetTime);
|
||||
if (currentEventIndex === -1) {
|
||||
currentEventIndex = data.recording.events.length;
|
||||
currentEventIndex = seekEvents.length;
|
||||
}
|
||||
|
||||
if (isPlaying) {
|
||||
@@ -548,11 +549,11 @@
|
||||
<div class="mt-4 pt-4 border-t border-border/50 grid grid-cols-3 gap-4 text-center">
|
||||
<div>
|
||||
<p class="text-xs text-muted-foreground">Events</p>
|
||||
<p class="text-sm font-medium">{data.recording.events.length}</p>
|
||||
<p class="text-sm font-medium">{data.recording.events?.length ?? 0}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs text-muted-foreground">Devices</p>
|
||||
<p class="text-sm font-medium">{data.recording.device_info.length}</p>
|
||||
<p class="text-sm font-medium">{data.recording.device_info?.length ?? 0}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs text-muted-foreground">Status</p>
|
||||
@@ -603,7 +604,7 @@
|
||||
{#if data.recording}
|
||||
<DeviceMappingDialog
|
||||
open={showMappingDialog}
|
||||
recordedDevices={data.recording.device_info}
|
||||
recordedDevices={(data.recording.device_info ?? []) as DeviceInfo[]}
|
||||
connectedDevices={devices}
|
||||
onConfirm={handleMappingConfirm}
|
||||
onCancel={handleMappingCancel}
|
||||
|
||||
Reference in New Issue
Block a user