Add paired devices support across CLI, core, and UI

- Add show_paired flag to device listing (CLI arg and input) - Extend
LibraryDeviceInfo with is_paired and is_connected; include Paired
devices in library listing when requested - Add Devices group to UI
(DevicesGroup) and hook into SpaceGroup - Extend device queries/types to
support show_paired and paired devices - Refactor Dockerfile to
multi-stage Bun + Rust builds; reuse web assets - Remove obsolete
core/ops/entries/mod.rs
This commit is contained in:
Jamie Pine
2025-11-24 05:22:54 -08:00
parent bcab31462e
commit 8808e85f4e
33 changed files with 1132 additions and 456 deletions

View File

@@ -11,6 +11,10 @@ pub struct DevicesListArgs {
/// Include detailed information (capabilities, network addresses, etc.)
#[arg(long, default_value_t = false)]
pub detailed: bool,
/// Show paired network devices in addition to library devices
#[arg(long, default_value_t = false)]
pub show_paired: bool,
}
impl DevicesListArgs {
@@ -18,6 +22,7 @@ impl DevicesListArgs {
ListLibraryDevicesInput {
include_offline: self.include_offline,
include_details: self.detailed,
show_paired: self.show_paired,
}
}
}

View File

@@ -1,9 +1,6 @@
# Spacedrive Server Docker Image
# Multi-stage build for minimal production image
ARG RUST_VERSION=1.83
ARG NODE_VERSION=22
#--
# Base image with common dependencies
#--
@@ -17,9 +14,37 @@ RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/
apt-get update && apt-get upgrade -y
#--
# Build environment
# Bun builder (for web assets)
#--
FROM base AS builder
FROM oven/bun:1.3-slim AS node-builder
WORKDIR /build
# Copy all source code first
COPY package.json bun.lock tsconfig.json ./
COPY packages ./packages
COPY apps/web ./apps/web
# Create placeholder for scripts workspace (referenced in package.json)
RUN mkdir -p scripts && echo '{"name":"scripts","private":true}' > scripts/package.json
# Install dependencies
# Note: Not using --frozen-lockfile because we add a placeholder scripts package
# Allow partial failures - some workspace packages may not install perfectly in Docker but web build will work
RUN bun install; exit 0
# Build ts-client package (required by web app)
WORKDIR /build/packages/ts-client
RUN bun run build
# Build web assets
WORKDIR /build/apps/web
RUN bun run build
#--
# Rust builder
#--
FROM base AS rust-builder
# Install build dependencies
RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \
@@ -35,14 +60,6 @@ RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal
ENV PATH="/root/.cargo/bin:$PATH"
# Install Node.js and pnpm
RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_VERSION}.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \
apt-get update && \
apt-get install -y nodejs
RUN npm install -g pnpm@latest
WORKDIR /build
# Copy workspace configuration
@@ -53,17 +70,11 @@ COPY .cargo ./.cargo
COPY core ./core
COPY crates ./crates
COPY apps/server ./apps/server
COPY apps/web ./apps/web
COPY packages ./packages
# Build web assets first
WORKDIR /build/apps/web
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
pnpm install --frozen-lockfile
RUN pnpm build
# Copy built web assets from node-builder
COPY --from=node-builder /build/apps/web/dist ./apps/web/dist
# Build server with embedded assets
WORKDIR /build
RUN --mount=type=cache,target=/root/.cargo/registry \
--mount=type=cache,target=/root/.cargo/git \
--mount=type=cache,target=/build/target \
@@ -76,7 +87,7 @@ RUN --mount=type=cache,target=/root/.cargo/registry \
FROM gcr.io/distroless/cc-debian12:nonroot
# Copy binary
COPY --from=builder /usr/local/bin/sd-server /usr/bin/sd-server
COPY --from=rust-builder /usr/local/bin/sd-server /usr/bin/sd-server
# Environment
ENV DATA_DIR=/data \

View File

File diff suppressed because one or more lines are too long

View File

@@ -2023,14 +2023,6 @@
"name"
],
"properties": {
"name": {
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
"type": "string"
},
"cmd": {
"description": "The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.",
"type": "string"
},
"args": {
"description": "The allowed arguments for the command execution.",
"allOf": [
@@ -2038,6 +2030,14 @@
"$ref": "#/definitions/ShellScopeEntryAllowedArgs"
}
]
},
"cmd": {
"description": "The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.",
"type": "string"
},
"name": {
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
"type": "string"
}
},
"additionalProperties": false
@@ -2049,10 +2049,6 @@
"sidecar"
],
"properties": {
"name": {
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
"type": "string"
},
"args": {
"description": "The allowed arguments for the command execution.",
"allOf": [
@@ -2061,6 +2057,10 @@
}
]
},
"name": {
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
"type": "string"
},
"sidecar": {
"description": "If this command is a sidecar command.",
"type": "boolean"
@@ -2083,14 +2083,6 @@
"name"
],
"properties": {
"name": {
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
"type": "string"
},
"cmd": {
"description": "The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.",
"type": "string"
},
"args": {
"description": "The allowed arguments for the command execution.",
"allOf": [
@@ -2098,6 +2090,14 @@
"$ref": "#/definitions/ShellScopeEntryAllowedArgs"
}
]
},
"cmd": {
"description": "The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.",
"type": "string"
},
"name": {
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
"type": "string"
}
},
"additionalProperties": false
@@ -2109,10 +2109,6 @@
"sidecar"
],
"properties": {
"name": {
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
"type": "string"
},
"args": {
"description": "The allowed arguments for the command execution.",
"allOf": [
@@ -2121,6 +2117,10 @@
}
]
},
"name": {
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
"type": "string"
},
"sidecar": {
"description": "If this command is a sidecar command.",
"type": "boolean"
@@ -6290,6 +6290,34 @@
}
]
},
"ShellScopeEntryAllowedArg": {
"description": "A command argument allowed to be executed by the webview API.",
"anyOf": [
{
"description": "A non-configurable argument that is passed to the command in the order it was specified.",
"type": "string"
},
{
"description": "A variable that is set while calling the command from the webview API.",
"type": "object",
"required": [
"validator"
],
"properties": {
"raw": {
"description": "Marks the validator as a raw regex, meaning the plugin should not make any modification at runtime.\n\nThis means the regex will not match on the entire string by default, which might be exploited if your regex allow unexpected input to be considered valid. When using this option, make sure your regex is correct.",
"default": false,
"type": "boolean"
},
"validator": {
"description": "[regex] validator to require passed values to conform to an expected input.\n\nThis will require the argument value passed to this variable to match the `validator` regex before it will be executed.\n\nThe regex string is by default surrounded by `^...$` to match the full string. For example the `https?://\\w+` regex would be registered as `^https?://\\w+$`.\n\n[regex]: <https://docs.rs/regex/latest/regex/#syntax>",
"type": "string"
}
},
"additionalProperties": false
}
]
},
"ShellScopeEntryAllowedArgs": {
"description": "A set of command arguments allowed to be executed by the webview API.\n\nA value of `true` will allow any arguments to be passed to the command. `false` will disable all arguments. A list of [`ShellScopeEntryAllowedArg`] will set those arguments as the only valid arguments to be passed to the attached command configuration.",
"anyOf": [
@@ -6305,34 +6333,6 @@
}
}
]
},
"ShellScopeEntryAllowedArg": {
"description": "A command argument allowed to be executed by the webview API.",
"anyOf": [
{
"description": "A non-configurable argument that is passed to the command in the order it was specified.",
"type": "string"
},
{
"description": "A variable that is set while calling the command from the webview API.",
"type": "object",
"required": [
"validator"
],
"properties": {
"validator": {
"description": "[regex] validator to require passed values to conform to an expected input.\n\nThis will require the argument value passed to this variable to match the `validator` regex before it will be executed.\n\nThe regex string is by default surrounded by `^...$` to match the full string. For example the `https?://\\w+` regex would be registered as `^https?://\\w+$`.\n\n[regex]: <https://docs.rs/regex/latest/regex/#syntax>",
"type": "string"
},
"raw": {
"description": "Marks the validator as a raw regex, meaning the plugin should not make any modification at runtime.\n\nThis means the regex will not match on the entire string by default, which might be exploited if your regex allow unexpected input to be considered valid. When using this option, make sure your regex is correct.",
"default": false,
"type": "boolean"
}
},
"additionalProperties": false
}
]
}
}
}

View File

@@ -2023,14 +2023,6 @@
"name"
],
"properties": {
"name": {
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
"type": "string"
},
"cmd": {
"description": "The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.",
"type": "string"
},
"args": {
"description": "The allowed arguments for the command execution.",
"allOf": [
@@ -2038,6 +2030,14 @@
"$ref": "#/definitions/ShellScopeEntryAllowedArgs"
}
]
},
"cmd": {
"description": "The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.",
"type": "string"
},
"name": {
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
"type": "string"
}
},
"additionalProperties": false
@@ -2049,10 +2049,6 @@
"sidecar"
],
"properties": {
"name": {
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
"type": "string"
},
"args": {
"description": "The allowed arguments for the command execution.",
"allOf": [
@@ -2061,6 +2057,10 @@
}
]
},
"name": {
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
"type": "string"
},
"sidecar": {
"description": "If this command is a sidecar command.",
"type": "boolean"
@@ -2083,14 +2083,6 @@
"name"
],
"properties": {
"name": {
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
"type": "string"
},
"cmd": {
"description": "The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.",
"type": "string"
},
"args": {
"description": "The allowed arguments for the command execution.",
"allOf": [
@@ -2098,6 +2090,14 @@
"$ref": "#/definitions/ShellScopeEntryAllowedArgs"
}
]
},
"cmd": {
"description": "The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.",
"type": "string"
},
"name": {
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
"type": "string"
}
},
"additionalProperties": false
@@ -2109,10 +2109,6 @@
"sidecar"
],
"properties": {
"name": {
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
"type": "string"
},
"args": {
"description": "The allowed arguments for the command execution.",
"allOf": [
@@ -2121,6 +2117,10 @@
}
]
},
"name": {
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
"type": "string"
},
"sidecar": {
"description": "If this command is a sidecar command.",
"type": "boolean"
@@ -6290,6 +6290,34 @@
}
]
},
"ShellScopeEntryAllowedArg": {
"description": "A command argument allowed to be executed by the webview API.",
"anyOf": [
{
"description": "A non-configurable argument that is passed to the command in the order it was specified.",
"type": "string"
},
{
"description": "A variable that is set while calling the command from the webview API.",
"type": "object",
"required": [
"validator"
],
"properties": {
"raw": {
"description": "Marks the validator as a raw regex, meaning the plugin should not make any modification at runtime.\n\nThis means the regex will not match on the entire string by default, which might be exploited if your regex allow unexpected input to be considered valid. When using this option, make sure your regex is correct.",
"default": false,
"type": "boolean"
},
"validator": {
"description": "[regex] validator to require passed values to conform to an expected input.\n\nThis will require the argument value passed to this variable to match the `validator` regex before it will be executed.\n\nThe regex string is by default surrounded by `^...$` to match the full string. For example the `https?://\\w+` regex would be registered as `^https?://\\w+$`.\n\n[regex]: <https://docs.rs/regex/latest/regex/#syntax>",
"type": "string"
}
},
"additionalProperties": false
}
]
},
"ShellScopeEntryAllowedArgs": {
"description": "A set of command arguments allowed to be executed by the webview API.\n\nA value of `true` will allow any arguments to be passed to the command. `false` will disable all arguments. A list of [`ShellScopeEntryAllowedArg`] will set those arguments as the only valid arguments to be passed to the attached command configuration.",
"anyOf": [
@@ -6305,34 +6333,6 @@
}
}
]
},
"ShellScopeEntryAllowedArg": {
"description": "A command argument allowed to be executed by the webview API.",
"anyOf": [
{
"description": "A non-configurable argument that is passed to the command in the order it was specified.",
"type": "string"
},
{
"description": "A variable that is set while calling the command from the webview API.",
"type": "object",
"required": [
"validator"
],
"properties": {
"validator": {
"description": "[regex] validator to require passed values to conform to an expected input.\n\nThis will require the argument value passed to this variable to match the `validator` regex before it will be executed.\n\nThe regex string is by default surrounded by `^...$` to match the full string. For example the `https?://\\w+` regex would be registered as `^https?://\\w+$`.\n\n[regex]: <https://docs.rs/regex/latest/regex/#syntax>",
"type": "string"
},
"raw": {
"description": "Marks the validator as a raw regex, meaning the plugin should not make any modification at runtime.\n\nThis means the regex will not match on the entire string by default, which might be exploited if your regex allow unexpected input to be considered valid. When using this option, make sure your regex is correct.",
"default": false,
"type": "boolean"
}
},
"additionalProperties": false
}
]
}
}
}

1
apps/web/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
dist/**/*

346
bun.lock
View File

@@ -154,6 +154,22 @@
"vite": "^5.4.9",
},
},
"apps/web": {
"name": "@sd/web",
"version": "0.1.0",
"dependencies": {
"@sd/interface": "workspace:*",
"react": "^19.0.0",
"react-dom": "^19.0.0",
},
"devDependencies": {
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@vitejs/plugin-react": "^4.3.4",
"typescript": "^5.7.2",
"vite": "^6.0.0",
},
},
"packages/assets": {
"name": "@sd/assets",
"version": "1.0.0",
@@ -613,9 +629,9 @@
"@babel/plugin-transform-react-jsx-development": ["@babel/plugin-transform-react-jsx-development@7.25.7", "", { "dependencies": { "@babel/plugin-transform-react-jsx": "7.25.7" }, "peerDependencies": { "@babel/core": "7.24.0" } }, "sha512-5yd3lH1PWxzW6IZj+p+Y4OLQzz0/LzlOG8vGqonHfVR3euf1vyzyMUJk9Ac+m97BH46mFc/98t9PmYLyvgL3qg=="],
"@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "7.26.5" }, "peerDependencies": { "@babel/core": "7.24.0" } }, "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg=="],
"@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="],
"@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "7.26.5" }, "peerDependencies": { "@babel/core": "7.24.0" } }, "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg=="],
"@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="],
"@babel/plugin-transform-react-pure-annotations": ["@babel/plugin-transform-react-pure-annotations@7.25.7", "", { "dependencies": { "@babel/helper-annotate-as-pure": "7.25.7", "@babel/helper-plugin-utils": "7.25.7" }, "peerDependencies": { "@babel/core": "7.24.0" } }, "sha512-6YTHJ7yjjgYqGc8S+CbEXhLICODk0Tn92j+vNJo07HFk9t3bjFgAKxPLFhHwF2NjmQVSI1zBRfBWUeVBa2osfA=="],
@@ -1405,6 +1421,8 @@
"@sd/ui": ["@sd/ui@workspace:packages/ui"],
"@sd/web": ["@sd/web@workspace:apps/web"],
"@segment/loosely-validate-event": ["@segment/loosely-validate-event@2.0.0", "", { "dependencies": { "component-type": "1.2.2", "join-component": "1.1.0" } }, "sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw=="],
"@sideway/address": ["@sideway/address@4.1.5", "", { "dependencies": { "@hapi/hoek": "9.3.0" } }, "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q=="],
@@ -1861,6 +1879,8 @@
"@vercel/edge-config-fs": ["@vercel/edge-config-fs@0.1.0", "", {}, "sha512-NRIBwfcS0bUoUbRWlNGetqjvLSwgYH/BqKqDN7vK1g32p7dN96k0712COgaz6VFizAm9b0g6IG6hR6+hc0KCPg=="],
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="],
"@vitejs/plugin-react-swc": ["@vitejs/plugin-react-swc@3.11.0", "", { "dependencies": { "@rolldown/pluginutils": "1.0.0-beta.27", "@swc/core": "^1.12.11" }, "peerDependencies": { "vite": "^4 || ^5 || ^6 || ^7" } }, "sha512-YTJCGFdNMHCMfjODYtxRNVAYmTWQ1Lb8PulP/2/f/oEEtglw8oKxKIZmmRkyXrVrHfsKOaVkAc3NT9/dMutO5w=="],
"@xmldom/xmldom": ["@xmldom/xmldom@0.8.10", "", {}, "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw=="],
@@ -2619,7 +2639,7 @@
"fbjs-css-vars": ["fbjs-css-vars@1.0.2", "", {}, "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ=="],
"fdir": ["fdir@6.4.0", "", { "optionalDependencies": { "picomatch": "4.0.2" } }, "sha512-3oB133prH1o4j/L5lLW7uOCF1PlD+/It2L0eL/iAqWMB91RBbqTewABqxhj0ibBd90EEmWZq7ntIWzVaWcXTGQ=="],
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
"fetch-retry": ["fetch-retry@4.1.1", "", {}, "sha512-e6eB7zN6UBSwGVwrbWVH+gdLnkW9WwHhmq2YDK1Sh30pzx1onRVGBvogTlUeWxwTa+L86NYdo4hFkh7O8ZjSnA=="],
@@ -3559,7 +3579,7 @@
"picocolors": ["picocolors@1.0.0", "", {}, "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="],
"picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="],
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="],
@@ -3693,7 +3713,7 @@
"react-reconciler": ["react-reconciler@0.27.0", "", { "dependencies": { "loose-envify": "1.4.0", "scheduler": "0.21.0" }, "peerDependencies": { "react": "18.3.1" } }, "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA=="],
"react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="],
"react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
"react-remove-scroll": ["react-remove-scroll@2.5.5", "", { "dependencies": { "react-remove-scroll-bar": "2.3.6", "react-style-singleton": "2.2.1", "tslib": "2.6.2", "use-callback-ref": "1.3.1", "use-sidecar": "1.1.2" }, "optionalDependencies": { "@types/react": "18.2.67" }, "peerDependencies": { "react": "18.2.0" } }, "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw=="],
@@ -4709,13 +4729,9 @@
"@babel/plugin-transform-react-jsx-development/@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.25.7", "", { "dependencies": { "@babel/helper-annotate-as-pure": "7.25.7", "@babel/helper-module-imports": "7.25.7", "@babel/helper-plugin-utils": "7.25.7", "@babel/plugin-syntax-jsx": "7.25.7", "@babel/types": "7.25.8" }, "peerDependencies": { "@babel/core": "7.24.0" } }, "sha512-vILAg5nwGlR9EXE8JIOX4NHXd49lrYbN8hnjffDtoULwpL9hUx/N55nqh2qd0q6FyNDfjl9V79ecKGvFbcSA0Q=="],
"@babel/plugin-transform-react-jsx-self/@babel/core": ["@babel/core@7.24.0", "", { "dependencies": { "@ampproject/remapping": "2.3.0", "@babel/code-frame": "7.23.5", "@babel/generator": "7.23.6", "@babel/helper-compilation-targets": "7.23.6", "@babel/helper-module-transforms": "7.23.3", "@babel/helpers": "7.24.0", "@babel/parser": "7.24.0", "@babel/template": "7.24.0", "@babel/traverse": "7.24.0", "@babel/types": "7.24.0", "convert-source-map": "2.0.0", "debug": "4.3.4", "gensync": "1.0.0-beta.2", "json5": "2.2.3", "semver": "6.3.1" } }, "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw=="],
"@babel/plugin-transform-react-jsx-self/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="],
"@babel/plugin-transform-react-jsx-self/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.26.5", "", {}, "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg=="],
"@babel/plugin-transform-react-jsx-source/@babel/core": ["@babel/core@7.24.0", "", { "dependencies": { "@ampproject/remapping": "2.3.0", "@babel/code-frame": "7.23.5", "@babel/generator": "7.23.6", "@babel/helper-compilation-targets": "7.23.6", "@babel/helper-module-transforms": "7.23.3", "@babel/helpers": "7.24.0", "@babel/parser": "7.24.0", "@babel/template": "7.24.0", "@babel/traverse": "7.24.0", "@babel/types": "7.24.0", "convert-source-map": "2.0.0", "debug": "4.3.4", "gensync": "1.0.0-beta.2", "json5": "2.2.3", "semver": "6.3.1" } }, "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw=="],
"@babel/plugin-transform-react-jsx-source/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.26.5", "", {}, "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg=="],
"@babel/plugin-transform-react-jsx-source/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="],
"@babel/plugin-transform-react-pure-annotations/@babel/core": ["@babel/core@7.24.0", "", { "dependencies": { "@ampproject/remapping": "2.3.0", "@babel/code-frame": "7.23.5", "@babel/generator": "7.23.6", "@babel/helper-compilation-targets": "7.23.6", "@babel/helper-module-transforms": "7.23.3", "@babel/helpers": "7.24.0", "@babel/parser": "7.24.0", "@babel/template": "7.24.0", "@babel/traverse": "7.24.0", "@babel/types": "7.24.0", "convert-source-map": "2.0.0", "debug": "4.3.4", "gensync": "1.0.0-beta.2", "json5": "2.2.3", "semver": "6.3.1" } }, "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw=="],
@@ -5219,6 +5235,10 @@
"@react-native/babel-preset/@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.25.9", "", { "dependencies": { "@babel/helper-annotate-as-pure": "7.25.9", "@babel/helper-module-imports": "7.25.9", "@babel/helper-plugin-utils": "7.26.5", "@babel/plugin-syntax-jsx": "7.25.9", "@babel/types": "7.26.5" }, "peerDependencies": { "@babel/core": "7.24.0" } }, "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw=="],
"@react-native/babel-preset/@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "7.26.5" }, "peerDependencies": { "@babel/core": "7.24.0" } }, "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg=="],
"@react-native/babel-preset/@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "7.26.5" }, "peerDependencies": { "@babel/core": "7.24.0" } }, "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg=="],
"@react-native/babel-preset/@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "7.26.5" }, "peerDependencies": { "@babel/core": "7.24.0" } }, "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng=="],
"@react-native/babel-preset/@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "7.26.5", "@babel/helper-skip-transparent-expression-wrappers": "7.25.9" }, "peerDependencies": { "@babel/core": "7.24.0" } }, "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A=="],
@@ -5231,6 +5251,8 @@
"@react-native/babel-preset/@babel/template": ["@babel/template@7.25.9", "", { "dependencies": { "@babel/code-frame": "7.26.2", "@babel/parser": "7.26.5", "@babel/types": "7.26.5" } }, "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg=="],
"@react-native/babel-preset/react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="],
"@react-native/codegen/@babel/parser": ["@babel/parser@7.26.5", "", { "dependencies": { "@babel/types": "7.26.5" }, "bin": "./bin/babel-parser.js" }, "sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw=="],
"@react-native/codegen/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "1.0.0", "inflight": "1.0.6", "inherits": "2.0.4", "minimatch": "3.1.2", "once": "1.4.0", "path-is-absolute": "1.0.1" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
@@ -5269,16 +5291,28 @@
"@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
"@rollup/pluginutils/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"@scalar/themes/@scalar/types": ["@scalar/types@0.1.7", "", { "dependencies": { "@scalar/openapi-types": "0.2.0", "@unhead/schema": "1.11.20", "nanoid": "5.1.6", "type-fest": "4.41.0", "zod": "3.23.8" } }, "sha512-irIDYzTQG2KLvFbuTI8k2Pz/R4JR+zUUSykVTbEMatkzMmVFnn1VzNSMlODbadycwZunbnL2tA27AXed9URVjw=="],
"@sd/interface/typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"@sd/landing/framer-motion": ["framer-motion@11.18.2", "", { "dependencies": { "motion-dom": "^11.18.1", "motion-utils": "^11.18.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w=="],
"@sd/ts-client/@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="],
"@sd/ts-client/typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"@sd/ui/@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="],
"@sd/ui/typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"@sd/web/@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="],
"@sd/web/@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
"@sd/web/typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"@sd/web/vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],
"@svgr/hast-util-to-babel-ast/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
"@svgr/webpack/@babel/core": ["@babel/core@7.24.0", "", { "dependencies": { "@ampproject/remapping": "2.3.0", "@babel/code-frame": "7.23.5", "@babel/generator": "7.23.6", "@babel/helper-compilation-targets": "7.23.6", "@babel/helper-module-transforms": "7.23.3", "@babel/helpers": "7.24.0", "@babel/parser": "7.24.0", "@babel/template": "7.24.0", "@babel/traverse": "7.24.0", "@babel/types": "7.24.0", "convert-source-map": "2.0.0", "debug": "4.3.4", "gensync": "1.0.0-beta.2", "json5": "2.2.3", "semver": "6.3.1" } }, "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw=="],
@@ -5343,6 +5377,8 @@
"@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@vitejs/plugin-react/@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="],
"acorn-globals/acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
"acorn-jsx/acorn": ["acorn@8.11.3", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg=="],
@@ -5399,6 +5435,8 @@
"babel-preset-expo/@babel/preset-typescript": ["@babel/preset-typescript@7.25.7", "", { "dependencies": { "@babel/helper-plugin-utils": "7.26.5", "@babel/helper-validator-option": "7.25.9", "@babel/plugin-syntax-jsx": "7.25.9", "@babel/plugin-transform-modules-commonjs": "7.26.3", "@babel/plugin-transform-typescript": "7.26.5" }, "peerDependencies": { "@babel/core": "7.24.0" } }, "sha512-rkkpaXJZOFN45Fb+Gki0c+KMIglk4+zZXOoMJuyEK8y8Kkc8Jd3BDmP7qPsz0zQMJj+UD7EprF+AqAXcILnexw=="],
"babel-preset-expo/react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="],
"better-auth/zod": ["zod@4.1.12", "", {}, "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ=="],
"bippy/@types/react-reconciler": ["@types/react-reconciler@0.28.9", "", { "peerDependencies": { "@types/react": "*" } }, "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg=="],
@@ -5851,6 +5889,8 @@
"react-native/pretty-format": ["pretty-format@26.6.2", "", { "dependencies": { "@jest/types": "26.6.2", "ansi-regex": "5.0.1", "ansi-styles": "4.3.0", "react-is": "17.0.2" } }, "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg=="],
"react-native/react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="],
"react-native/regenerator-runtime": ["regenerator-runtime@0.13.11", "", {}, "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="],
"react-native/scheduler": ["scheduler@0.24.0-canary-efb381bbf-20230505", "", { "dependencies": { "loose-envify": "1.4.0" } }, "sha512-ABvovCDe/k9IluqSh4/ISoq8tIJnW8euVAWYt5j/bg6dRnqwQwiGO1F/V4AyK96NGF/FB04FhOUDuWj8IKfABA=="],
@@ -5979,6 +6019,10 @@
"test-exclude/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "1.0.0", "inflight": "1.0.6", "inherits": "2.0.4", "minimatch": "3.1.2", "once": "1.4.0", "path-is-absolute": "1.0.1" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
"tinyglobby/fdir": ["fdir@6.4.0", "", { "optionalDependencies": { "picomatch": "4.0.2" } }, "sha512-3oB133prH1o4j/L5lLW7uOCF1PlD+/It2L0eL/iAqWMB91RBbqTewABqxhj0ibBd90EEmWZq7ntIWzVaWcXTGQ=="],
"tinyglobby/picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="],
"tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "1.2.8" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="],
"tsup/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
@@ -7935,46 +7979,6 @@
"@babel/plugin-transform-react-jsx-development/@babel/plugin-transform-react-jsx/@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.25.7", "", { "dependencies": { "@babel/helper-plugin-utils": "7.25.7" }, "peerDependencies": { "@babel/core": "7.24.0" } }, "sha512-ruZOnKO+ajVL/MVx+PwNBPOkrnXTXoWMtte1MBpegfCArhqOe3Bj52avVj1huLLxNKYKXYaSxZ2F+woK1ekXfw=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/code-frame": ["@babel/code-frame@7.23.5", "", { "dependencies": { "@babel/highlight": "7.23.4", "chalk": "2.4.2" } }, "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/generator": ["@babel/generator@7.23.6", "", { "dependencies": { "@babel/types": "7.24.0", "@jridgewell/gen-mapping": "0.3.5", "@jridgewell/trace-mapping": "0.3.25", "jsesc": "2.5.2" } }, "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.23.6", "", { "dependencies": { "@babel/compat-data": "7.23.5", "@babel/helper-validator-option": "7.23.5", "browserslist": "4.23.0", "lru-cache": "5.1.1", "semver": "6.3.1" } }, "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.23.3", "", { "dependencies": { "@babel/helper-environment-visitor": "7.22.20", "@babel/helper-module-imports": "7.22.15", "@babel/helper-simple-access": "7.22.5", "@babel/helper-split-export-declaration": "7.22.6", "@babel/helper-validator-identifier": "7.22.20" }, "peerDependencies": { "@babel/core": "7.24.0" } }, "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/helpers": ["@babel/helpers@7.24.0", "", { "dependencies": { "@babel/template": "7.24.0", "@babel/traverse": "7.24.0", "@babel/types": "7.24.0" } }, "sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/parser": ["@babel/parser@7.24.0", "", { "dependencies": { "@babel/types": "7.24.0" }, "bin": "./bin/babel-parser.js" }, "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/template": ["@babel/template@7.24.0", "", { "dependencies": { "@babel/code-frame": "7.23.5", "@babel/parser": "7.24.0", "@babel/types": "7.24.0" } }, "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/types": ["@babel/types@7.24.0", "", { "dependencies": { "@babel/helper-string-parser": "7.23.4", "@babel/helper-validator-identifier": "7.22.20", "to-fast-properties": "2.0.0" } }, "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/debug": ["debug@4.3.4", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/code-frame": ["@babel/code-frame@7.23.5", "", { "dependencies": { "@babel/highlight": "7.23.4", "chalk": "2.4.2" } }, "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/generator": ["@babel/generator@7.23.6", "", { "dependencies": { "@babel/types": "7.24.0", "@jridgewell/gen-mapping": "0.3.5", "@jridgewell/trace-mapping": "0.3.25", "jsesc": "2.5.2" } }, "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.23.6", "", { "dependencies": { "@babel/compat-data": "7.23.5", "@babel/helper-validator-option": "7.23.5", "browserslist": "4.23.0", "lru-cache": "5.1.1", "semver": "6.3.1" } }, "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.23.3", "", { "dependencies": { "@babel/helper-environment-visitor": "7.22.20", "@babel/helper-module-imports": "7.22.15", "@babel/helper-simple-access": "7.22.5", "@babel/helper-split-export-declaration": "7.22.6", "@babel/helper-validator-identifier": "7.22.20" }, "peerDependencies": { "@babel/core": "7.24.0" } }, "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/helpers": ["@babel/helpers@7.24.0", "", { "dependencies": { "@babel/template": "7.24.0", "@babel/traverse": "7.24.0", "@babel/types": "7.24.0" } }, "sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/parser": ["@babel/parser@7.24.0", "", { "dependencies": { "@babel/types": "7.24.0" }, "bin": "./bin/babel-parser.js" }, "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/template": ["@babel/template@7.24.0", "", { "dependencies": { "@babel/code-frame": "7.23.5", "@babel/parser": "7.24.0", "@babel/types": "7.24.0" } }, "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/types": ["@babel/types@7.24.0", "", { "dependencies": { "@babel/helper-string-parser": "7.23.4", "@babel/helper-validator-identifier": "7.22.20", "to-fast-properties": "2.0.0" } }, "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/debug": ["debug@4.3.4", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@babel/plugin-transform-react-jsx/@babel/core/@babel/code-frame": ["@babel/code-frame@7.23.5", "", { "dependencies": { "@babel/highlight": "7.23.4", "chalk": "2.4.2" } }, "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA=="],
"@babel/plugin-transform-react-jsx/@babel/core/@babel/generator": ["@babel/generator@7.23.6", "", { "dependencies": { "@babel/types": "7.24.0", "@jridgewell/gen-mapping": "0.3.5", "@jridgewell/trace-mapping": "0.3.25", "jsesc": "2.5.2" } }, "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw=="],
@@ -8681,6 +8685,10 @@
"@react-native/babel-preset/@babel/plugin-transform-react-jsx/@babel/types": ["@babel/types@7.26.5", "", { "dependencies": { "@babel/helper-string-parser": "7.25.9", "@babel/helper-validator-identifier": "7.25.9" } }, "sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg=="],
"@react-native/babel-preset/@babel/plugin-transform-react-jsx-self/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.26.5", "", {}, "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg=="],
"@react-native/babel-preset/@babel/plugin-transform-react-jsx-source/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.26.5", "", {}, "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg=="],
"@react-native/babel-preset/@babel/plugin-transform-shorthand-properties/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.26.5", "", {}, "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg=="],
"@react-native/babel-preset/@babel/plugin-transform-spread/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.26.5", "", {}, "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg=="],
@@ -8767,6 +8775,14 @@
"@sd/ui/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@sd/web/vite/esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
"@sd/web/vite/postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
"@sd/web/vite/rollup": ["rollup@4.53.2", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.53.2", "@rollup/rollup-android-arm64": "4.53.2", "@rollup/rollup-darwin-arm64": "4.53.2", "@rollup/rollup-darwin-x64": "4.53.2", "@rollup/rollup-freebsd-arm64": "4.53.2", "@rollup/rollup-freebsd-x64": "4.53.2", "@rollup/rollup-linux-arm-gnueabihf": "4.53.2", "@rollup/rollup-linux-arm-musleabihf": "4.53.2", "@rollup/rollup-linux-arm64-gnu": "4.53.2", "@rollup/rollup-linux-arm64-musl": "4.53.2", "@rollup/rollup-linux-loong64-gnu": "4.53.2", "@rollup/rollup-linux-ppc64-gnu": "4.53.2", "@rollup/rollup-linux-riscv64-gnu": "4.53.2", "@rollup/rollup-linux-riscv64-musl": "4.53.2", "@rollup/rollup-linux-s390x-gnu": "4.53.2", "@rollup/rollup-linux-x64-gnu": "4.53.2", "@rollup/rollup-linux-x64-musl": "4.53.2", "@rollup/rollup-openharmony-arm64": "4.53.2", "@rollup/rollup-win32-arm64-msvc": "4.53.2", "@rollup/rollup-win32-ia32-msvc": "4.53.2", "@rollup/rollup-win32-x64-gnu": "4.53.2", "@rollup/rollup-win32-x64-msvc": "4.53.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g=="],
"@sd/web/vite/tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
"@svgr/webpack/@babel/core/@babel/code-frame": ["@babel/code-frame@7.23.5", "", { "dependencies": { "@babel/highlight": "7.23.4", "chalk": "2.4.2" } }, "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA=="],
"@svgr/webpack/@babel/core/@babel/generator": ["@babel/generator@7.23.6", "", { "dependencies": { "@babel/types": "7.24.0", "@jridgewell/gen-mapping": "0.3.5", "@jridgewell/trace-mapping": "0.3.25", "jsesc": "2.5.2" } }, "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw=="],
@@ -8813,6 +8829,28 @@
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "1.0.2" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
"@vitejs/plugin-react/@babel/core/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
"@vitejs/plugin-react/@babel/core/@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="],
"@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="],
"@vitejs/plugin-react/@babel/core/@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="],
"@vitejs/plugin-react/@babel/core/@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="],
"@vitejs/plugin-react/@babel/core/@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="],
"@vitejs/plugin-react/@babel/core/@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="],
"@vitejs/plugin-react/@babel/core/@babel/traverse": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="],
"@vitejs/plugin-react/@babel/core/@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="],
"@vitejs/plugin-react/@babel/core/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"@vitejs/plugin-react/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"ansi-fragments/strip-ansi/ansi-regex": ["ansi-regex@4.1.1", "", {}, "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="],
"ast-transform/escodegen/estraverse": ["estraverse@1.5.1", "", {}, "sha512-FpCjJDfmo3vsc/1zKSeqR5k42tcIhxFIlvq+h9j0fO2q/h2uLKyweq7rYJ+0CoVvrGQOxIS5wyBrW/+vF58BUQ=="],
@@ -9639,10 +9677,6 @@
"tsup/rollup/@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"tsup/tinyglobby/fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
"tsup/tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
"tsx/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="],
@@ -11713,50 +11747,6 @@
"@babel/plugin-transform-react-jsx-development/@babel/core/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/code-frame/@babel/highlight": ["@babel/highlight@7.23.4", "", { "dependencies": { "@babel/helper-validator-identifier": "7.25.7", "chalk": "2.4.2", "js-tokens": "4.0.0" } }, "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/code-frame/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "3.2.1", "escape-string-regexp": "1.0.5", "supports-color": "5.5.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/generator/jsesc": ["jsesc@2.5.2", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/helper-compilation-targets/@babel/compat-data": ["@babel/compat-data@7.23.5", "", {}, "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "3.1.1" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/helper-module-transforms/@babel/helper-module-imports": ["@babel/helper-module-imports@7.22.15", "", { "dependencies": { "@babel/types": "7.24.0" } }, "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/helper-module-transforms/@babel/helper-simple-access": ["@babel/helper-simple-access@7.22.5", "", { "dependencies": { "@babel/types": "7.24.0" } }, "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/helper-module-transforms/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.22.20", "", {}, "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.23.4", "", {}, "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.22.20", "", {}, "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/code-frame/@babel/highlight": ["@babel/highlight@7.23.4", "", { "dependencies": { "@babel/helper-validator-identifier": "7.25.7", "chalk": "2.4.2", "js-tokens": "4.0.0" } }, "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/code-frame/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "3.2.1", "escape-string-regexp": "1.0.5", "supports-color": "5.5.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/generator/jsesc": ["jsesc@2.5.2", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/helper-compilation-targets/@babel/compat-data": ["@babel/compat-data@7.23.5", "", {}, "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "3.1.1" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/helper-module-transforms/@babel/helper-module-imports": ["@babel/helper-module-imports@7.22.15", "", { "dependencies": { "@babel/types": "7.24.0" } }, "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/helper-module-transforms/@babel/helper-simple-access": ["@babel/helper-simple-access@7.22.5", "", { "dependencies": { "@babel/types": "7.24.0" } }, "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/helper-module-transforms/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.22.20", "", {}, "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.23.4", "", {}, "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.22.20", "", {}, "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
"@babel/plugin-transform-react-jsx/@babel/core/@babel/code-frame/@babel/highlight": ["@babel/highlight@7.23.4", "", { "dependencies": { "@babel/helper-validator-identifier": "7.25.7", "chalk": "2.4.2", "js-tokens": "4.0.0" } }, "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A=="],
"@babel/plugin-transform-react-jsx/@babel/core/@babel/code-frame/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "3.2.1", "escape-string-regexp": "1.0.5", "supports-color": "5.5.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="],
@@ -12469,6 +12459,88 @@
"@sd/ui/@babel/core/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
"@sd/web/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
"@sd/web/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="],
"@sd/web/vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="],
"@sd/web/vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="],
"@sd/web/vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="],
"@sd/web/vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="],
"@sd/web/vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="],
"@sd/web/vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="],
"@sd/web/vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="],
"@sd/web/vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="],
"@sd/web/vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="],
"@sd/web/vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="],
"@sd/web/vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="],
"@sd/web/vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="],
"@sd/web/vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="],
"@sd/web/vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="],
"@sd/web/vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="],
"@sd/web/vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="],
"@sd/web/vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="],
"@sd/web/vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="],
"@sd/web/vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="],
"@sd/web/vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="],
"@sd/web/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
"@sd/web/vite/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"@sd/web/vite/postcss/picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"@sd/web/vite/rollup/@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.53.2", "", { "os": "android", "cpu": "arm" }, "sha512-yDPzwsgiFO26RJA4nZo8I+xqzh7sJTZIWQOxn+/XOdPE31lAvLIYCKqjV+lNH/vxE2L2iH3plKxDCRK6i+CwhA=="],
"@sd/web/vite/rollup/@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.53.2", "", { "os": "android", "cpu": "arm64" }, "sha512-k8FontTxIE7b0/OGKeSN5B6j25EuppBcWM33Z19JoVT7UTXFSo3D9CdU39wGTeb29NO3XxpMNauh09B+Ibw+9g=="],
"@sd/web/vite/rollup/@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.53.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-A6s4gJpomNBtJ2yioj8bflM2oogDwzUiMl2yNJ2v9E7++sHrSrsQ29fOfn5DM/iCzpWcebNYEdXpaK4tr2RhfQ=="],
"@sd/web/vite/rollup/@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.53.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-e6XqVmXlHrBlG56obu9gDRPW3O3hLxpwHpLsBJvuI8qqnsrtSZ9ERoWUXtPOkY8c78WghyPHZdmPhHLWNdAGEw=="],
"@sd/web/vite/rollup/@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.53.2", "", { "os": "linux", "cpu": "arm" }, "sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg=="],
"@sd/web/vite/rollup/@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.53.2", "", { "os": "linux", "cpu": "arm" }, "sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q=="],
"@sd/web/vite/rollup/@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.53.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA=="],
"@sd/web/vite/rollup/@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.53.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ=="],
"@sd/web/vite/rollup/@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.53.2", "", { "os": "linux", "cpu": "none" }, "sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA=="],
"@sd/web/vite/rollup/@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.53.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w=="],
"@sd/web/vite/rollup/@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.53.2", "", { "os": "linux", "cpu": "x64" }, "sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw=="],
"@sd/web/vite/rollup/@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.53.2", "", { "os": "linux", "cpu": "x64" }, "sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA=="],
"@sd/web/vite/rollup/@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.53.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-IlbHFYc/pQCgew/d5fslcy1KEaYVCJ44G8pajugd8VoOEI8ODhtb/j8XMhLpwHCMB3yk2J07ctup10gpw2nyMA=="],
"@sd/web/vite/rollup/@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.53.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-lNlPEGgdUfSzdCWU176ku/dQRnA7W+Gp8d+cWv73jYrb8uT7HTVVxq62DUYxjbaByuf1Yk0RIIAbDzp+CnOTFg=="],
"@sd/web/vite/rollup/@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.53.2", "", { "os": "win32", "cpu": "x64" }, "sha512-k+/Rkcyx//P6fetPoLMb8pBeqJBNGx81uuf7iljX9++yNBVRDQgD04L+SVXmXmh5ZP4/WOp4mWF0kmi06PW2tA=="],
"@sd/web/vite/rollup/@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@svgr/webpack/@babel/core/@babel/code-frame/@babel/highlight": ["@babel/highlight@7.23.4", "", { "dependencies": { "@babel/helper-validator-identifier": "7.25.7", "chalk": "2.4.2", "js-tokens": "4.0.0" } }, "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A=="],
"@svgr/webpack/@babel/core/@babel/code-frame/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "3.2.1", "escape-string-regexp": "1.0.5", "supports-color": "5.5.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="],
@@ -12491,6 +12563,32 @@
"@svgr/webpack/@babel/core/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
"@vitejs/plugin-react/@babel/core/@babel/code-frame/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
"@vitejs/plugin-react/@babel/core/@babel/code-frame/picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"@vitejs/plugin-react/@babel/core/@babel/generator/@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
"@vitejs/plugin-react/@babel/core/@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
"@vitejs/plugin-react/@babel/core/@babel/generator/jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
"@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/@babel/compat-data": ["@babel/compat-data@7.28.5", "", {}, "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA=="],
"@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
"@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/browserslist": ["browserslist@4.24.4", "", { "dependencies": { "caniuse-lite": "1.0.30001692", "electron-to-chromium": "1.5.80", "node-releases": "2.0.19", "update-browserslist-db": "1.1.2" }, "bin": { "browserslist": "cli.js" } }, "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A=="],
"@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "3.1.1" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"@vitejs/plugin-react/@babel/core/@babel/helper-module-transforms/@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="],
"@vitejs/plugin-react/@babel/core/@babel/helper-module-transforms/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
"@vitejs/plugin-react/@babel/core/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
"@vitejs/plugin-react/@babel/core/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
"babel-plugin-istanbul/istanbul-lib-instrument/@babel/parser/@babel/types": ["@babel/types@7.26.5", "", { "dependencies": { "@babel/helper-string-parser": "7.25.9", "@babel/helper-validator-identifier": "7.25.9" } }, "sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg=="],
"babel-plugin-polyfill-corejs2/@babel/core/@babel/code-frame/@babel/highlight": ["@babel/highlight@7.23.4", "", { "dependencies": { "@babel/helper-validator-identifier": "7.25.7", "chalk": "2.4.2", "js-tokens": "4.0.0" } }, "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A=="],
@@ -13629,22 +13727,6 @@
"@babel/plugin-transform-react-jsx-development/@babel/core/@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/code-frame/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "1.9.3" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/code-frame/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/code-frame/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/code-frame/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "1.9.3" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/code-frame/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/code-frame/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
"@babel/plugin-transform-react-jsx/@babel/core/@babel/code-frame/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "1.9.3" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
"@babel/plugin-transform-react-jsx/@babel/core/@babel/code-frame/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
@@ -14087,6 +14169,20 @@
"@svgr/webpack/@babel/core/@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
"@vitejs/plugin-react/@babel/core/@babel/generator/@jridgewell/gen-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
"@vitejs/plugin-react/@babel/core/@babel/generator/@jridgewell/trace-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
"@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/browserslist/caniuse-lite": ["caniuse-lite@1.0.30001692", "", {}, "sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A=="],
"@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/browserslist/electron-to-chromium": ["electron-to-chromium@1.5.80", "", {}, "sha512-LTrKpW0AqIuHwmlVNV+cjFYTnXtM9K37OGhpe0ZI10ScPSxqVSryZHIY3WnCS5NSYbBODRTZyhRMS2h5FAEqAw=="],
"@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/browserslist/node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="],
"@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.2", "", { "dependencies": { "escalade": "3.2.0", "picocolors": "1.1.1" }, "peerDependencies": { "browserslist": "4.24.4" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg=="],
"@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
"babel-plugin-istanbul/istanbul-lib-instrument/@babel/parser/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="],
"babel-plugin-istanbul/istanbul-lib-instrument/@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="],
@@ -14697,14 +14793,6 @@
"@babel/plugin-transform-react-jsx-development/@babel/core/@babel/code-frame/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/code-frame/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/code-frame/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/code-frame/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/code-frame/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
"@babel/plugin-transform-react-jsx/@babel/core/@babel/code-frame/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
"@babel/plugin-transform-react-jsx/@babel/core/@babel/code-frame/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
@@ -14959,6 +15047,10 @@
"@svgr/webpack/@babel/core/@babel/code-frame/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
"@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/browserslist/update-browserslist-db/escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
"@vitejs/plugin-react/@babel/core/@babel/helper-compilation-targets/browserslist/update-browserslist-db/picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"babel-plugin-polyfill-corejs2/@babel/core/@babel/code-frame/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
"babel-plugin-polyfill-corejs2/@babel/core/@babel/code-frame/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
@@ -15303,10 +15395,6 @@
"@babel/plugin-transform-react-jsx-development/@babel/core/@babel/code-frame/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
"@babel/plugin-transform-react-jsx-self/@babel/core/@babel/code-frame/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
"@babel/plugin-transform-react-jsx-source/@babel/core/@babel/code-frame/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
"@babel/plugin-transform-react-jsx/@babel/core/@babel/code-frame/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
"@babel/plugin-transform-react-pure-annotations/@babel/core/@babel/code-frame/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],

View File

@@ -202,6 +202,155 @@ impl crate::domain::resource::Identifiable for File {
// Media data types - for now return empty, can be implemented later
"image_media_data" | "video_media_data" | "audio_media_data" => Ok(vec![]),
// Pattern 3: Route from user_metadata_tag to affected files
"user_metadata_tag" => {
use crate::infra::db::entities::user_metadata;
// Get the user_metadata_tag to find its parent user_metadata
let umt = crate::infra::db::entities::user_metadata_tag::Entity::find()
.filter(crate::infra::db::entities::user_metadata_tag::Column::Uuid.eq(dependency_id))
.one(db)
.await?
.ok_or_else(|| {
crate::common::errors::CoreError::NotFound(format!(
"UserMetadataTag {} not found",
dependency_id
))
})?;
// Get the parent user_metadata
let metadata = user_metadata::Entity::find_by_id(umt.user_metadata_id)
.one(db)
.await?
.ok_or_else(|| {
crate::common::errors::CoreError::NotFound(format!(
"UserMetadata {} not found",
umt.user_metadata_id
))
})?;
// Route based on metadata scope (entry-scoped or content-scoped)
if let Some(entry_uuid) = metadata.entry_uuid {
// Entry-scoped: affects only this entry
Ok(vec![entry_uuid])
} else if let Some(content_uuid) = metadata.content_identity_uuid {
// Content-scoped: affects all entries with this content
let ci = content_identity::Entity::find()
.filter(content_identity::Column::Uuid.eq(content_uuid))
.one(db)
.await?
.ok_or_else(|| {
crate::common::errors::CoreError::NotFound(format!(
"ContentIdentity {} not found",
content_uuid
))
})?;
let entries = entry::Entity::find()
.filter(entry::Column::ContentId.eq(ci.id))
.all(db)
.await?;
Ok(entries.into_iter().filter_map(|e| e.uuid).collect())
} else {
Ok(vec![])
}
}
// Pattern 3: Route from user_metadata to affected files
"user_metadata" => {
use crate::infra::db::entities::user_metadata;
let metadata = user_metadata::Entity::find()
.filter(user_metadata::Column::Uuid.eq(dependency_id))
.one(db)
.await?
.ok_or_else(|| {
crate::common::errors::CoreError::NotFound(format!(
"UserMetadata {} not found",
dependency_id
))
})?;
// Route based on metadata scope
if let Some(entry_uuid) = metadata.entry_uuid {
Ok(vec![entry_uuid])
} else if let Some(content_uuid) = metadata.content_identity_uuid {
let ci = content_identity::Entity::find()
.filter(content_identity::Column::Uuid.eq(content_uuid))
.one(db)
.await?
.ok_or_else(|| {
crate::common::errors::CoreError::NotFound(format!(
"ContentIdentity {} not found",
content_uuid
))
})?;
let entries = entry::Entity::find()
.filter(entry::Column::ContentId.eq(ci.id))
.all(db)
.await?;
Ok(entries.into_iter().filter_map(|e| e.uuid).collect())
} else {
Ok(vec![])
}
}
// Pattern 4: Route from tag changes (affects all files with this tag)
"tag" => {
use crate::infra::db::entities::{user_metadata, user_metadata_tag};
// Find all user_metadata_tag records with this tag
let tag_model = crate::infra::db::entities::tag::Entity::find()
.filter(crate::infra::db::entities::tag::Column::Uuid.eq(dependency_id))
.one(db)
.await?
.ok_or_else(|| {
crate::common::errors::CoreError::NotFound(format!(
"Tag {} not found",
dependency_id
))
})?;
let metadata_tags = user_metadata_tag::Entity::find()
.filter(user_metadata_tag::Column::TagId.eq(tag_model.id))
.all(db)
.await?;
let mut affected_entries = Vec::new();
for umt in metadata_tags {
// Get the parent user_metadata
if let Some(metadata) = user_metadata::Entity::find_by_id(umt.user_metadata_id)
.one(db)
.await?
{
// Route based on metadata scope
if let Some(entry_uuid) = metadata.entry_uuid {
affected_entries.push(entry_uuid);
} else if let Some(content_uuid) = metadata.content_identity_uuid {
// Content-scoped: get all entries with this content
if let Some(ci) = content_identity::Entity::find()
.filter(content_identity::Column::Uuid.eq(content_uuid))
.one(db)
.await?
{
let entries = entry::Entity::find()
.filter(entry::Column::ContentId.eq(ci.id))
.all(db)
.await?;
affected_entries.extend(entries.into_iter().filter_map(|e| e.uuid));
}
}
}
}
Ok(affected_entries)
}
_ => Ok(vec![]),
}
}

View File

@@ -143,6 +143,9 @@ pub enum GroupType {
/// Device with its volumes and locations as children
Device { device_id: Uuid },
/// All devices (library and paired) across the system
Devices,
/// All locations across all devices
Locations,

View File

@@ -37,40 +37,22 @@ impl Library {
/// foreign keys are already UUIDs.
///
/// **Examples**: Tag, Device, Album
///
/// **Note**: This only handles sync (cross-device replication). Resource events
/// for frontend reactivity are emitted separately by ResourceManager when it
/// detects sync changes via the transaction manager.
pub async fn sync_model<M: Syncable>(&self, model: &M, change_type: ChangeType) -> Result<()> {
let data = model
.to_sync_json()
.map_err(|e| anyhow::anyhow!("Failed to serialize model: {}", e))?;
let result = if crate::infra::sync::is_device_owned(M::SYNC_MODEL).await {
self.sync_device_owned_internal(M::SYNC_MODEL, model.sync_id(), data.clone())
if crate::infra::sync::is_device_owned(M::SYNC_MODEL).await {
self.sync_device_owned_internal(M::SYNC_MODEL, model.sync_id(), data)
.await
} else {
self.sync_shared_internal(M::SYNC_MODEL, model.sync_id(), change_type, data.clone())
self.sync_shared_internal(M::SYNC_MODEL, model.sync_id(), change_type, data)
.await
};
// Emit resource event for frontend reactivity
if result.is_ok() {
use crate::infra::sync::ChangeType as CT;
match change_type {
CT::Delete => {
self.event_bus().emit(Event::ResourceDeleted {
resource_type: M::SYNC_MODEL.to_string(),
resource_id: model.sync_id(),
});
}
CT::Insert | CT::Update => {
self.event_bus().emit(Event::ResourceChanged {
resource_type: M::SYNC_MODEL.to_string(),
resource: data,
metadata: None,
});
}
}
}
result
}
/// Sync a model with FK conversion (for models with relationships)
@@ -79,6 +61,10 @@ impl Library {
/// Required for proper sync of related data.
///
/// **Examples**: Location (has device_id, entry_id), Entry (has parent_id, metadata_id)
///
/// **Note**: This only handles sync (cross-device replication). Resource events
/// for frontend reactivity are emitted separately by ResourceManager when it
/// detects sync changes via the transaction manager.
pub async fn sync_model_with_db<M: Syncable>(
&self,
model: &M,
@@ -141,35 +127,13 @@ impl Library {
}
}
let result = if crate::infra::sync::is_device_owned(M::SYNC_MODEL).await {
self.sync_device_owned_internal(M::SYNC_MODEL, model.sync_id(), data.clone())
if crate::infra::sync::is_device_owned(M::SYNC_MODEL).await {
self.sync_device_owned_internal(M::SYNC_MODEL, model.sync_id(), data)
.await
} else {
self.sync_shared_internal(M::SYNC_MODEL, model.sync_id(), change_type, data.clone())
self.sync_shared_internal(M::SYNC_MODEL, model.sync_id(), change_type, data)
.await
};
// Emit resource event for frontend reactivity
if result.is_ok() {
use crate::infra::sync::ChangeType as CT;
match change_type {
CT::Delete => {
self.event_bus().emit(Event::ResourceDeleted {
resource_type: M::SYNC_MODEL.to_string(),
resource_id: model.sync_id(),
});
}
CT::Insert | CT::Update => {
self.event_bus().emit(Event::ResourceChanged {
resource_type: M::SYNC_MODEL.to_string(),
resource: data,
metadata: None,
});
}
}
}
result
}
/// Batch sync multiple models (optimized for bulk operations)

View File

@@ -221,7 +221,17 @@ impl LocationManager {
path: location_path.clone(),
});
// Resource events are now automatically emitted by sync_model_with_db above
// Emit resource events via ResourceManager (builds proper domain model)
let resource_manager = crate::domain::ResourceManager::new(
std::sync::Arc::new(library.db().conn().clone()),
std::sync::Arc::new(self.events.clone()),
);
if let Err(e) = resource_manager
.emit_resource_events("location", vec![location_id])
.await
{
warn!("Failed to emit location resource events: {}", e);
}
// Also emit indexing started event
self.events.emit(Event::IndexingStarted { location_id });

View File

@@ -43,4 +43,12 @@ pub struct LibraryDeviceInfo {
/// Device capabilities (if available)
pub capabilities: Option<serde_json::Value>,
/// Whether this device is only paired (not registered in library)
#[serde(default)]
pub is_paired: bool,
/// Whether this device is currently connected via network (only relevant for paired devices)
#[serde(default)]
pub is_connected: bool,
}

View File

@@ -19,6 +19,10 @@ pub struct ListLibraryDevicesInput {
/// Whether to include detailed capabilities and sync leadership info (default: false)
pub include_details: bool,
/// Whether to also include paired network devices (default: false)
#[serde(default)]
pub show_paired: bool,
}
/// Query to list all devices from the library database
@@ -34,6 +38,7 @@ impl ListLibraryDevicesQuery {
input: ListLibraryDevicesInput {
include_offline: true,
include_details: false,
show_paired: false,
},
}
}
@@ -44,6 +49,7 @@ impl ListLibraryDevicesQuery {
input: ListLibraryDevicesInput {
include_offline: true,
include_details: true,
show_paired: false,
},
}
}
@@ -54,6 +60,7 @@ impl ListLibraryDevicesQuery {
input: ListLibraryDevicesInput {
include_offline: false,
include_details: false,
show_paired: false,
},
}
}
@@ -133,9 +140,61 @@ impl LibraryQuery for ListLibraryDevicesQuery {
is_current: device.uuid == current_device_id,
network_addresses,
capabilities,
is_paired: false,
is_connected: false,
});
}
// If show_paired is true, also fetch paired network devices
if self.input.show_paired {
// Get networking service
if let Some(networking) = context.get_networking().await {
let device_registry = networking.device_registry();
let registry = device_registry.read().await;
let all_devices = registry.get_all_devices();
for (device_id, state) in all_devices {
// Skip if this device is already in the library
if result.iter().any(|d| d.id == device_id) {
continue;
}
use crate::service::network::device::DeviceState;
let (device_info, is_connected) = match state {
DeviceState::Paired { info, .. } => (Some(info), false),
DeviceState::Connected { info, .. } => (Some(info), true),
DeviceState::Disconnected { info, .. } => (Some(info), false),
_ => (None, false),
};
if let Some(info) = device_info {
// Filter by online status if requested
if !self.input.include_offline && !is_connected {
continue;
}
result.push(LibraryDeviceInfo {
id: device_id,
name: info.device_name.clone(),
os: format!("{:?}", info.device_type),
os_version: Some(info.os_version.clone()),
hardware_model: None,
is_online: is_connected,
last_seen_at: info.last_seen,
created_at: info.last_seen, // Use last_seen as fallback
updated_at: info.last_seen,
is_current: false,
network_addresses: Vec::new(),
capabilities: None,
is_paired: true,
is_connected,
});
}
}
}
}
Ok(result)
}
}

View File

@@ -1 +0,0 @@

View File

@@ -71,6 +71,9 @@ impl LibraryAction for ApplyTagsAction {
})
.collect();
// Collect affected entry UUIDs for resource events
let mut affected_entry_uuids = Vec::new();
// Handle both content-based and entry-based tagging
match &self.input.targets {
TagTargets::Content(content_ids) => {
@@ -82,13 +85,31 @@ impl LibraryAction for ApplyTagsAction {
{
Ok(models) => {
successfully_tagged_count += 1;
// Sync each user_metadata_tag model
// Sync each user_metadata_tag model (for cross-device sync)
for model in models {
library
.sync_model(&model, crate::infra::sync::ChangeType::Insert)
.await
.map_err(|e| ActionError::Internal(format!("Failed to sync tag association: {}", e)))?;
}
// Find all entries with this content_id to emit resource events
use crate::infra::db::entities::{content_identity, entry};
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
if let Ok(Some(ci)) = content_identity::Entity::find()
.filter(content_identity::Column::Uuid.eq(content_id))
.one(db.conn())
.await
{
if let Ok(entries) = entry::Entity::find()
.filter(entry::Column::ContentId.eq(ci.id))
.all(db.conn())
.await
{
affected_entry_uuids.extend(entries.into_iter().filter_map(|e| e.uuid));
}
}
}
Err(e) => {
warnings.push(format!("Failed to tag content {}: {}", content_id, e));
@@ -111,13 +132,16 @@ impl LibraryAction for ApplyTagsAction {
{
Ok(models) => {
successfully_tagged_count += 1;
// Sync each user_metadata_tag model
// Sync each user_metadata_tag model (for cross-device sync)
for model in models {
library
.sync_model(&model, crate::infra::sync::ChangeType::Insert)
.await
.map_err(|e| ActionError::Internal(format!("Failed to sync tag association: {}", e)))?;
}
// Track this entry for resource events
affected_entry_uuids.push(entry_uuid);
}
Err(e) => {
warnings.push(format!("Failed to tag entry {}: {}", entry_id, e));
@@ -127,6 +151,20 @@ impl LibraryAction for ApplyTagsAction {
}
}
// Emit resource events for affected files (frontend reactivity)
if !affected_entry_uuids.is_empty() {
let resource_manager = crate::domain::ResourceManager::new(
Arc::new(db.conn().clone()),
_context.events.clone(),
);
if let Err(e) = resource_manager
.emit_resource_events("file", affected_entry_uuids)
.await
{
tracing::warn!("Failed to emit file resource events after tagging: {}", e);
}
}
let output = ApplyTagsOutput::success(
successfully_tagged_count,
self.input.tag_ids.len(),

View File

@@ -88,6 +88,8 @@ impl LibraryAction for CreateTagAction {
device_uuid: device_id,
};
let mut affected_entry_uuids = Vec::new();
match targets {
ApplyToTargets::Content(content_ids) => {
// Apply to content identities (all instances)
@@ -97,13 +99,31 @@ impl LibraryAction for CreateTagAction {
.await
.map_err(|e| ActionError::Internal(format!("Failed to apply tag to content: {}", e)))?;
// Sync each user_metadata_tag model
// Sync each user_metadata_tag model (for cross-device sync)
for model in models {
library
.sync_model(&model, ChangeType::Insert)
.await
.map_err(|e| ActionError::Internal(format!("Failed to sync tag association: {}", e)))?;
}
// Find all entries with this content_id for resource events
use crate::infra::db::entities::{content_identity, entry};
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
if let Ok(Some(ci)) = content_identity::Entity::find()
.filter(content_identity::Column::Uuid.eq(content_id))
.one(library.db().conn())
.await
{
if let Ok(entries) = entry::Entity::find()
.filter(entry::Column::ContentId.eq(ci.id))
.all(library.db().conn())
.await
{
affected_entry_uuids.extend(entries.into_iter().filter_map(|e| e.uuid));
}
}
}
}
ApplyToTargets::Entry(entry_ids) => {
@@ -120,16 +140,33 @@ impl LibraryAction for CreateTagAction {
.await
.map_err(|e| ActionError::Internal(format!("Failed to apply tag to entry: {}", e)))?;
// Sync each user_metadata_tag model
// Sync each user_metadata_tag model (for cross-device sync)
for model in models {
library
.sync_model(&model, ChangeType::Insert)
.await
.map_err(|e| ActionError::Internal(format!("Failed to sync tag association: {}", e)))?;
}
// Track this entry for resource events
affected_entry_uuids.push(entry_uuid);
}
}
}
// Emit resource events for affected files (frontend reactivity)
if !affected_entry_uuids.is_empty() {
let resource_manager = crate::domain::ResourceManager::new(
Arc::new(library.db().conn().clone()),
_context.events.clone(),
);
if let Err(e) = resource_manager
.emit_resource_events("file", affected_entry_uuids)
.await
{
tracing::warn!("Failed to emit file resource events after tag creation: {}", e);
}
}
}
Ok(CreateTagOutput::from_entity(&tag_entity))

View File

@@ -237,7 +237,10 @@ impl LibraryQuery for VolumeListQuery {
volume_items.push(super::output::VolumeItem {
id: vol.id,
name: vol.name.clone(),
name: vol
.display_name
.clone()
.unwrap_or_else(|| vol.name.clone()),
fingerprint: vol.fingerprint.clone(),
volume_type: format!("{:?}", vol.volume_type),
mount_point: Some(vol.mount_point.to_string_lossy().to_string()),
@@ -271,7 +274,10 @@ impl LibraryQuery for VolumeListQuery {
volume_items.push(super::output::VolumeItem {
id: vol.id,
name: vol.name.clone(),
name: vol
.display_name
.clone()
.unwrap_or_else(|| vol.name.clone()),
fingerprint: vol.fingerprint.clone(),
volume_type: format!("{:?}", vol.volume_type),
mount_point: Some(vol.mount_point.to_string_lossy().to_string()),

View File

@@ -385,6 +385,13 @@ pub fn containers_to_volumes(
}
}
// Determine display name - show "Macintosh HD" for the main Data volume
let display_name = if mount_point.to_string_lossy() == "/System/Volumes/Data" {
"Macintosh HD".to_string()
} else {
volume_info.name.clone()
};
let volume = Volume {
id: uuid::Uuid::new_v4(),
fingerprint,
@@ -418,7 +425,7 @@ pub fn containers_to_volumes(
total_files: None,
total_directories: None,
last_stats_update: None,
display_name: Some(volume_info.name.clone()),
display_name: Some(display_name),
is_favorite: false,
color: None,
icon: None,
@@ -501,6 +508,10 @@ fn should_be_user_visible(
name: &str,
) -> bool {
let mount_str = mount_point.to_string_lossy();
debug!(
"VISIBILITY: Checking volume: name='{}' role={:?} mount='{}'",
name, role, mount_str
);
// Hide system utility volumes
match role {
@@ -524,8 +535,12 @@ fn should_be_user_visible(
return false;
}
// Hide home autofs mounts
if mount_str.contains("/home") && name.to_lowercase() == "home" {
// Hide home autofs mounts (e.g., /System/Volumes/Data/home)
if name.to_lowercase() == "home" && mount_str.ends_with("/home") {
debug!(
"VISIBILITY: Hiding home volume: name='{}' mount='{}'",
name, mount_str
);
return false;
}

View File

@@ -1387,16 +1387,22 @@ impl VolumeManager {
}
if !self.is_volume_tracked(library, &volume.fingerprint).await? {
// Use display_name if available, otherwise fall back to name
let display_name = volume
.display_name
.clone()
.unwrap_or_else(|| volume.name.clone());
match self
.track_volume(library, &volume.fingerprint, Some(volume.name.clone()))
.track_volume(library, &volume.fingerprint, Some(display_name.clone()))
.await
{
Ok(tracked_volume) => {
info!("Auto-tracked volume: {}", volume.name);
info!("Auto-tracked volume: {}", display_name);
tracked_volumes.push(tracked_volume);
}
Err(e) => {
warn!("Failed to auto-track volume {}: {}", volume.name, e);
warn!("Failed to auto-track volume {}: {}", display_name, e);
}
}
}

View File

@@ -87,6 +87,9 @@ pub async fn detect_non_apfs_volumes(
let fingerprint =
VolumeFingerprint::new(&name, total_bytes, &file_system.to_string());
// Check if volume should be user-visible
let is_user_visible = should_be_user_visible(&mount_path, &name);
// Auto-track eligibility: Primary, UserData, System volumes
// Also track Secondary volumes if they're system mounts
let auto_track_eligible = matches!(
@@ -124,7 +127,7 @@ pub async fn detect_non_apfs_volumes(
apfs_container: None,
container_volume_id: None,
path_mappings: Vec::new(),
is_user_visible: true,
is_user_visible,
auto_track_eligible,
read_speed_mbps: None,
write_speed_mbps: None,
@@ -234,6 +237,32 @@ fn detect_filesystem(mount_point: &PathBuf) -> VolumeResult<FileSystem> {
}
}
/// Determine if a non-APFS volume should be visible to the user
fn should_be_user_visible(mount_point: &PathBuf, name: &str) -> bool {
let mount_str = mount_point.to_string_lossy();
// Hide home autofs mounts (e.g., /System/Volumes/Data/home)
if name.to_lowercase() == "home" && mount_str.ends_with("/home") {
debug!(
"VISIBILITY: Hiding home volume (non-APFS): name='{}' mount='{}'",
name, mount_str
);
return false;
}
// Hide iOS Simulator volumes
if mount_str.starts_with("/Library/Developer/CoreSimulator") {
return false;
}
// Hide snapshot mounts
if mount_str.contains("@") {
return false;
}
true
}
/// Get volume space information using df
pub fn get_volume_space_info(mount_point: &PathBuf) -> VolumeResult<(u64, u64)> {
let output = Command::new("df")

View File

@@ -9,6 +9,7 @@
"exports": {
".": "./src/index.tsx",
"./app": "./src/App.tsx",
"./platform": "./src/platform.tsx",
"./styles.css": "./src/styles.css"
},
"scripts": {

View File

@@ -1,4 +1,4 @@
import { ShinyButton } from "@sd/ui/ShinyButton";
import { ShinyButton } from "@sd/ui";
import { SpacedriveProvider } from "./context";
import { useLibraries } from "./hooks/useLibraries";
import { useAllEvents } from "./hooks/useEvent";

View File

@@ -11,7 +11,7 @@ import {
useDialog,
TopBarButton,
} from "@sd/ui";
import * as Tabs from "@sd/ui/Tabs";
import { Tabs } from "@sd/ui";
import type {
IndexMode,
LocationAddInput,

View File

@@ -16,7 +16,7 @@ import {
useDialog,
TopBarButton,
} from "@sd/ui";
import * as Tabs from "@sd/ui/Tabs";
import { Tabs } from "@sd/ui";
import type {
IndexMode,
LocationAddInput,
@@ -319,15 +319,18 @@ function AddStorageDialog(props: {
const addLocation = useLibraryMutation("locations.add");
const addCloudVolume = useLibraryMutation("volumes.add_cloud");
const trackVolume = useLibraryMutation("volumes.track");
const { data: suggestedLocations } = useLibraryQuery({
type: "locations.suggested",
input: null,
});
const { data: volumes } = useLibraryQuery({
const { data: volumesData } = useLibraryQuery({
type: "volumes.list",
input: { filter: "UntrackedOnly" },
});
const volumes = volumesData?.volumes || [];
const localForm = useForm<LocalFolderFormData>({
defaultValues: {
path: "",
@@ -426,6 +429,38 @@ function AddStorageDialog(props: {
setStep("local-config");
};
const handleVolumeSelect = async (volume: any) => {
try {
// Step 1: Track the volume
const trackResult = await trackVolume.mutateAsync({
fingerprint: volume.fingerprint,
display_name: volume.name,
});
// Step 2: Create a location for the volume's mount point
const locationInput: LocationAddInput = {
path: {
Physical: {
device_slug: "local",
path: volume.mount_point || "/",
},
},
name: volume.name,
mode: "Deep",
job_policies: {},
};
const locationResult = await addLocation.mutateAsync(locationInput);
dialog.state.open = false;
if (locationResult?.id && props.onStorageAdded) {
props.onStorageAdded(locationResult.id);
}
} catch (error) {
console.error("Failed to track volume and add location:", error);
}
};
const onSubmitLocal = localForm.handleSubmit(async (data) => {
const job_policies: any = {};
selectedJobs.forEach((jobId) => {
@@ -750,6 +785,7 @@ function AddStorageDialog(props: {
<button
key={volume.fingerprint}
type="button"
onClick={() => handleVolumeSelect(volume)}
className={clsx(
"w-full flex items-center gap-3 rounded-lg border p-3 text-left",
"transition-all hover:scale-[1.01]",
@@ -766,7 +802,7 @@ function AddStorageDialog(props: {
</div>
</div>
<div className="text-xs text-ink-dull">
{(volume.total_capacity_bytes / 1e9).toFixed(0)} GB
{volume.total_capacity ? (volume.total_capacity / 1e9).toFixed(0) : '?'} GB
</div>
</button>
))}

View File

@@ -43,6 +43,7 @@ function AddGroupDialog(props: { id: number; spaceId: string }) {
onChange={(e) => setGroupType(e.target.value as GroupType)}
className="w-full rounded-lg border border-app-line bg-app-input px-3 py-2 text-sm text-ink"
>
<option value="Devices">All Devices</option>
<option value="Locations">All Locations</option>
<option value="Tags">Tags</option>
<option value="Cloud">Cloud Storage</option>
@@ -65,6 +66,7 @@ function AddGroupDialog(props: { id: number; spaceId: string }) {
}
function getDefaultName(groupType: GroupType): string {
if (groupType === 'Devices') return 'Devices';
if (groupType === 'Locations') return 'Locations';
if (groupType === 'Tags') return 'Tags';
if (groupType === 'Cloud') return 'Cloud';

View File

@@ -0,0 +1,114 @@
import { CaretRight, Desktop, WifiHigh } from "@phosphor-icons/react";
import clsx from "clsx";
import { useNavigate } from "react-router-dom";
import { useLibraryQuery } from "../../context";
import NodeIcon from "@sd/assets/icons/Node.png";
import LaptopIcon from "@sd/assets/icons/Laptop.png";
import MobileIcon from "@sd/assets/icons/Mobile.png";
import PCIcon from "@sd/assets/icons/PC.png";
interface DevicesGroupProps {
isCollapsed: boolean;
onToggle: () => void;
}
// Helper to get icon based on OS
function getDeviceIcon(os: string): string {
const osLower = os.toLowerCase();
if (osLower.includes("mac") || osLower.includes("darwin")) {
return LaptopIcon;
}
if (osLower.includes("ios") || osLower.includes("android")) {
return MobileIcon;
}
if (osLower.includes("windows") || osLower.includes("linux")) {
return PCIcon;
}
return NodeIcon;
}
export function DevicesGroup({ isCollapsed, onToggle }: DevicesGroupProps) {
const navigate = useNavigate();
const { data: devices, isLoading } = useLibraryQuery({
type: "devices.list",
input: {
include_offline: true,
include_details: false,
show_paired: true,
},
});
return (
<div>
{/* Header */}
<button
onClick={onToggle}
className="mb-1 flex w-full cursor-default items-center gap-2 px-1 text-xs font-semibold uppercase tracking-wider text-sidebar-ink-faint hover:text-sidebar-ink"
>
<CaretRight
className={clsx("transition-transform", !isCollapsed && "rotate-90")}
size={10}
weight="bold"
/>
<span>Devices</span>
{devices && devices.length > 0 && (
<span className="ml-auto text-sidebar-ink-faint">{devices.length}</span>
)}
</button>
{/* Items */}
{!isCollapsed && (
<div className="space-y-0.5">
{isLoading ? (
<div className="px-2 py-1 text-xs text-sidebar-ink-faint">Loading...</div>
) : !devices || devices.length === 0 ? (
<div className="px-2 py-1 text-xs text-sidebar-ink-faint">No devices</div>
) : (
devices.map((device) => (
<button
key={device.id}
onClick={() => navigate(`/device/${device.id}`)}
className={clsx(
"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm font-medium",
device.is_current
? "bg-sidebar-selected/30 text-sidebar-ink"
: "text-sidebar-inkDull hover:text-sidebar-ink hover:bg-sidebar-box transition-colors"
)}
>
{/* Device Icon */}
<img src={getDeviceIcon(device.os)} alt="" className="size-4" />
{/* Device Name */}
<span className="flex-1 truncate text-left">{device.name}</span>
{/* Status Indicators */}
<div className="flex items-center gap-1">
{/* Paired indicator (network icon) */}
{device.is_paired && (
<WifiHigh
size={12}
weight="bold"
className="text-accent"
title="Paired via network"
/>
)}
{/* Offline indicator */}
{!device.is_online && !device.is_connected && (
<span className="text-xs text-ink-faint">Offline</span>
)}
{/* Connected indicator for paired devices */}
{device.is_paired && device.is_connected && (
<span className="text-xs text-accent">Connected</span>
)}
</div>
</button>
))
)}
</div>
)}
</div>
);
}

View File

@@ -25,7 +25,7 @@ export function LocationsGroup({ isCollapsed, onToggle }: LocationsGroupProps) {
{/* Header */}
<button
onClick={onToggle}
className="mb-1 flex w-full items-center gap-2 px-1 text-xs font-semibold uppercase tracking-wider text-sidebar-ink-faint hover:text-sidebar-ink"
className="mb-1 flex w-full cursor-default items-center gap-2 px-1 text-xs font-semibold uppercase tracking-wider text-sidebar-ink-faint hover:text-sidebar-ink"
>
<CaretRight
className={clsx("transition-transform", !isCollapsed && "rotate-90")}

View File

@@ -5,9 +5,10 @@ import type {
SpaceItem as SpaceItemType,
GroupType,
} from '@sd/ts-client';
import { useSidebarStore } from '@sd/ts-client/stores/sidebar';
import { useSidebarStore } from '@sd/ts-client';
import { SpaceItem } from './SpaceItem';
import { DeviceGroup } from './DeviceGroup';
import { DevicesGroup } from './DevicesGroup';
import { LocationsGroup } from './LocationsGroup';
import { VolumesGroup } from './VolumesGroup';
import { TagsGroup } from './TagsGroup';
@@ -34,6 +35,11 @@ export function SpaceGroup({ group, items }: SpaceGroupProps) {
);
}
// Devices group - fetches all devices (library + paired)
if (group.group_type === 'Devices') {
return <DevicesGroup isCollapsed={isCollapsed} onToggle={() => toggleGroup(group.id)} />;
}
// Locations group - fetches all locations
if (group.group_type === 'Locations') {
return <LocationsGroup isCollapsed={isCollapsed} onToggle={() => toggleGroup(group.id)} />;

View File

@@ -26,6 +26,8 @@ interface SpaceItemProps {
onClick?: () => void;
/** Volume data for constructing explorer path */
volumeData?: { device_slug: string; mount_path: string };
/** Optional custom icon (as image path) to override default icon */
customIcon?: string;
}
function getItemIcon(itemType: ItemType): any {
@@ -99,6 +101,7 @@ export function SpaceItem({
iconWeight = "bold",
onClick,
volumeData,
customIcon,
}: SpaceItemProps) {
const navigate = useNavigate();
const location = useLocation();
@@ -121,7 +124,18 @@ export function SpaceItem({
path = getItemPath(item.item_type, volumeData);
}
const isActive = location.pathname === path;
// Override with custom icon if provided
if (customIcon) {
iconData = { type: "image", icon: customIcon };
}
// Check if this item is active
// For paths with query params (like volumes), compare full path including search
const isActive = path
? path.includes("?")
? location.pathname + location.search === path
: location.pathname === path
: false;
const handleClick = () => {
if (onClick) {

View File

@@ -3,7 +3,18 @@ import clsx from "clsx";
import { useNavigate } from "react-router-dom";
import { useNormalizedCache } from "@sd/ts-client";
import { SpaceItem } from "./SpaceItem";
import type { VolumeItem } from "@sd/ts-client";
import type { VolumeItem, CloudServiceType } from "@sd/ts-client";
// Import cloud provider icons
import DriveAmazonS3 from "@sd/assets/icons/Drive-AmazonS3.png";
import DriveGoogleDrive from "@sd/assets/icons/Drive-GoogleDrive.png";
import DriveDropbox from "@sd/assets/icons/Drive-Dropbox.png";
import DriveOneDrive from "@sd/assets/icons/Drive-OneDrive.png";
import DriveBackBlaze from "@sd/assets/icons/Drive-BackBlaze.png";
import DrivePCloud from "@sd/assets/icons/Drive-PCloud.png";
import DriveBox from "@sd/assets/icons/Drive-Box.png";
import HDDIcon from "@sd/assets/icons/HDD.png";
import DriveIcon from "@sd/assets/icons/Drive.png";
interface VolumesGroupProps {
isCollapsed: boolean;
@@ -12,6 +23,60 @@ interface VolumesGroupProps {
filter?: "TrackedOnly" | "UntrackedOnly" | "All";
}
// Map cloud service types to icons
const cloudProviderIcons: Record<CloudServiceType, string> = {
s3: DriveAmazonS3,
gdrive: DriveGoogleDrive,
dropbox: DriveDropbox,
onedrive: DriveOneDrive,
gcs: DriveGoogleDrive,
azblob: DriveBox,
b2: DriveBackBlaze,
wasabi: DriveAmazonS3,
spaces: DriveAmazonS3,
cloud: DrivePCloud,
};
// Helper to parse cloud service from volume fingerprint
function parseCloudService(volume: VolumeItem): CloudServiceType | null {
// Check if this is a cloud volume by looking at mount_point pattern
const mountPoint = volume.mount_point;
if (!mountPoint) return null;
// Parse mount_point for cloud service (format: "s3://bucket-name")
const match = mountPoint.match(/^(\w+):\/\//);
if (!match) return null;
const scheme = match[1];
// Verify it's a cloud scheme (not file:// or other local schemes)
if (scheme === "s3" || scheme === "gdrive" || scheme === "dropbox" ||
scheme === "onedrive" || scheme === "gcs" || scheme === "azblob" ||
scheme === "b2" || scheme === "wasabi" || scheme === "spaces" ||
scheme === "cloud") {
return scheme as CloudServiceType;
}
return null;
}
// Get icon for a volume based on its type
function getVolumeIcon(volume: VolumeItem): string {
// Check if it's a cloud volume (by mount_point pattern or filesystem type)
const cloudService = parseCloudService(volume);
if (cloudService) {
return cloudProviderIcons[cloudService] || DriveIcon;
}
// For external drives, use HDD icon
if (volume.volume_type === "External") {
return HDDIcon;
}
// Default to generic drive icon
return DriveIcon;
}
export function VolumesGroup({
isCollapsed,
onToggle,
@@ -44,16 +109,13 @@ export function VolumesGroup({
{/* Group Header */}
<button
onClick={onToggle}
className="mb-1 flex w-full items-center gap-2 px-1 text-xs font-semibold uppercase tracking-wider text-sidebar-ink-faint hover:text-sidebar-ink"
className="mb-1 flex w-full cursor-default items-center gap-2 px-1 text-xs font-semibold uppercase tracking-wider text-sidebar-ink-faint hover:text-sidebar-ink"
>
<div
className={clsx(
"transition-transform",
!isCollapsed && "rotate-90",
)}
>
<CaretRight size={10} weight="bold" />
</div>
<CaretRight
className={clsx("transition-transform", !isCollapsed && "rotate-90")}
size={10}
weight="bold"
/>
<span>Volumes</span>
</button>
@@ -84,14 +146,7 @@ export function VolumesGroup({
mount_path: volume.mount_point || "/",
}}
rightComponent={getVolumeBadges(volume)}
className={
volume.is_tracked
? "text-sidebar-inkDull hover:text-sidebar-ink hover:bg-sidebar-selected transition-colors"
: "text-sidebar-ink-faint hover:text-sidebar-inkDull hover:bg-sidebar-box transition-colors"
}
iconWeight={
volume.is_tracked ? "bold" : "regular"
}
customIcon={getVolumeIcon(volume)}
/>
))
)}

View File

@@ -1,7 +1,7 @@
import { useState, useEffect } from "react";
import { GearSix } from "@phosphor-icons/react";
import { useNavigate } from "react-router-dom";
import { useSidebarStore } from "@sd/ts-client/stores/sidebar";
import { useSidebarStore } from "@sd/ts-client";
import { useSpaces, useSpaceLayout } from "./hooks/useSpaces";
import { SpaceSwitcher } from "./SpaceSwitcher";
import { SpaceGroup } from "./SpaceGroup";

View File

@@ -6,12 +6,16 @@
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
"types": "./src/index.ts",
"default": "./src/index.ts"
},
"./generated/types": {
"types": "./dist/generated/types.d.ts",
"default": "./dist/generated/types.js"
"types": "./src/generated/types.ts",
"default": "./src/generated/types.ts"
},
"./hooks": {
"types": "./src/hooks/index.ts",
"default": "./src/hooks/index.ts"
}
},
"scripts": {

View File

@@ -876,6 +876,10 @@ export type GroupType =
* Device with its volumes and locations as children
*/
{ Device: { device_id: string } } |
/**
* All devices (library and paired) across the system
*/
"Devices" |
/**
* All locations across all devices
*/
@@ -1375,7 +1379,15 @@ network_addresses: string[];
/**
* Device capabilities (if available)
*/
capabilities: JsonValue | null };
capabilities: JsonValue | null;
/**
* Whether this device is only paired (not registered in library)
*/
is_paired?: boolean;
/**
* Whether this device is currently connected via network (only relevant for paired devices)
*/
is_connected?: boolean };
/**
* Input for exporting a library
@@ -1680,7 +1692,11 @@ include_offline: boolean;
/**
* Whether to include detailed capabilities and sync leadership info (default: false)
*/
include_details: boolean };
include_details: boolean;
/**
* Whether to also include paired network devices (default: false)
*/
show_paired?: boolean };
export type ListPairedDevicesInput = {
/**
@@ -3213,92 +3229,92 @@ success: boolean };
// ===== API Type Unions =====
export type CoreAction =
{ type: 'models.whisper.delete'; input: DeleteWhisperModelInput; output: DeleteWhisperModelOutput }
| { type: 'models.whisper.download'; input: DownloadWhisperModelInput; output: DownloadWhisperModelOutput }
{ type: 'network.start'; input: NetworkStartInput; output: NetworkStartOutput }
| { type: 'network.device.revoke'; input: DeviceRevokeInput; output: DeviceRevokeOutput }
| { type: 'libraries.delete'; input: LibraryDeleteInput; output: LibraryDeleteOutput }
| { type: 'network.stop'; input: NetworkStopInput; output: NetworkStopOutput }
| { type: 'network.sync_setup'; input: LibrarySyncSetupInput; output: LibrarySyncSetupOutput }
| { type: 'libraries.open'; input: LibraryOpenInput; output: LibraryOpenOutput }
| { type: 'network.pair.generate'; input: PairGenerateInput; output: PairGenerateOutput }
| { type: 'network.spacedrop.send'; input: SpacedropSendInput; output: SpacedropSendOutput }
| { type: 'network.pair.generate'; input: PairGenerateInput; output: PairGenerateOutput }
| { type: 'libraries.delete'; input: LibraryDeleteInput; output: LibraryDeleteOutput }
| { type: 'network.sync_setup'; input: LibrarySyncSetupInput; output: LibrarySyncSetupOutput }
| { type: 'models.whisper.delete'; input: DeleteWhisperModelInput; output: DeleteWhisperModelOutput }
| { type: 'models.whisper.download'; input: DownloadWhisperModelInput; output: DownloadWhisperModelOutput }
| { type: 'libraries.create'; input: LibraryCreateInput; output: LibraryCreateOutput }
| { type: 'libraries.open'; input: LibraryOpenInput; output: LibraryOpenOutput }
| { type: 'network.pair.join'; input: PairJoinInput; output: PairJoinOutput }
| { type: 'network.pair.cancel'; input: PairCancelInput; output: PairCancelOutput }
| { type: 'network.start'; input: NetworkStartInput; output: NetworkStartOutput }
| { type: 'libraries.create'; input: LibraryCreateInput; output: LibraryCreateOutput }
;
export type LibraryAction =
{ type: 'spaces.add_group'; input: AddGroupInput; output: AddGroupOutput }
| { type: 'spaces.update_group'; input: UpdateGroupInput; output: UpdateGroupOutput }
| { type: 'locations.remove'; input: LocationRemoveInput; output: LocationRemoveOutput }
| { type: 'indexing.verify'; input: IndexVerifyInput; output: IndexVerifyOutput }
{ type: 'media.thumbstrip.generate'; input: GenerateThumbstripInput; output: GenerateThumbstripOutput }
| { type: 'tags.create'; input: CreateTagInput; output: CreateTagOutput }
| { type: 'volumes.add_cloud'; input: VolumeAddCloudInput; output: VolumeAddCloudOutput }
| { type: 'locations.add'; input: LocationAddInput; output: LocationAddOutput }
| { type: 'files.copy'; input: FileCopyInput; output: JobReceipt }
| { type: 'tags.apply'; input: ApplyTagsInput; output: ApplyTagsOutput }
| { type: 'jobs.pause'; input: JobPauseInput; output: JobPauseOutput }
| { type: 'spaces.create'; input: SpaceCreateInput; output: SpaceCreateOutput }
| { type: 'libraries.export'; input: LibraryExportInput; output: LibraryExportOutput }
| { type: 'libraries.rename'; input: LibraryRenameInput; output: LibraryRenameOutput }
| { type: 'jobs.resume'; input: JobResumeInput; output: JobResumeOutput }
| { type: 'files.delete'; input: FileDeleteInput; output: JobReceipt }
| { type: 'locations.update'; input: LocationUpdateInput; output: LocationUpdateOutput }
| { type: 'locations.rescan'; input: LocationRescanInput; output: LocationRescanOutput }
| { type: 'media.speech.transcribe'; input: TranscribeAudioInput; output: TranscribeAudioOutput }
| { type: 'spaces.add_item'; input: AddItemInput; output: AddItemOutput }
| { type: 'spaces.reorder_items'; input: ReorderItemsInput; output: ReorderOutput }
| { type: 'spaces.reorder_groups'; input: ReorderGroupsInput; output: ReorderOutput }
| { type: 'spaces.update'; input: SpaceUpdateInput; output: SpaceUpdateOutput }
| { type: 'volumes.track'; input: VolumeTrackInput; output: VolumeTrackOutput }
| { type: 'spaces.create'; input: SpaceCreateInput; output: SpaceCreateOutput }
| { type: 'spaces.delete_item'; input: DeleteItemInput; output: DeleteItemOutput }
| { type: 'media.thumbstrip.generate'; input: GenerateThumbstripInput; output: GenerateThumbstripOutput }
| { type: 'tags.create'; input: CreateTagInput; output: CreateTagOutput }
| { type: 'indexing.start'; input: IndexInput; output: JobReceipt }
| { type: 'jobs.cancel'; input: JobCancelInput; output: JobCancelOutput }
| { type: 'jobs.pause'; input: JobPauseInput; output: JobPauseOutput }
| { type: 'files.delete'; input: FileDeleteInput; output: JobReceipt }
| { type: 'media.speech.transcribe'; input: TranscribeAudioInput; output: TranscribeAudioOutput }
| { type: 'volumes.speed_test'; input: VolumeSpeedTestInput; output: VolumeSpeedTestOutput }
| { type: 'locations.update'; input: LocationUpdateInput; output: LocationUpdateOutput }
| { type: 'jobs.resume'; input: JobResumeInput; output: JobResumeOutput }
| { type: 'spaces.add_item'; input: AddItemInput; output: AddItemOutput }
| { type: 'media.proxy.generate'; input: GenerateProxyInput; output: GenerateProxyOutput }
| { type: 'locations.add'; input: LocationAddInput; output: LocationAddOutput }
| { type: 'locations.triggerJob'; input: LocationTriggerJobInput; output: LocationTriggerJobOutput }
| { type: 'libraries.export'; input: LibraryExportInput; output: LibraryExportOutput }
| { type: 'tags.apply'; input: ApplyTagsInput; output: ApplyTagsOutput }
| { type: 'libraries.rename'; input: LibraryRenameInput; output: LibraryRenameOutput }
| { type: 'spaces.delete'; input: SpaceDeleteInput; output: SpaceDeleteOutput }
| { type: 'volumes.remove_cloud'; input: VolumeRemoveCloudInput; output: VolumeRemoveCloudOutput }
| { type: 'volumes.track'; input: VolumeTrackInput; output: VolumeTrackOutput }
| { type: 'spaces.add_group'; input: AddGroupInput; output: AddGroupOutput }
| { type: 'spaces.update_group'; input: UpdateGroupInput; output: UpdateGroupOutput }
| { type: 'indexing.verify'; input: IndexVerifyInput; output: IndexVerifyOutput }
| { type: 'spaces.update'; input: SpaceUpdateInput; output: SpaceUpdateOutput }
| { type: 'volumes.untrack'; input: VolumeUntrackInput; output: VolumeUntrackOutput }
| { type: 'volumes.refresh'; input: VolumeRefreshInput; output: VolumeRefreshOutput }
| { type: 'media.proxy.generate'; input: GenerateProxyInput; output: GenerateProxyOutput }
| { type: 'volumes.speed_test'; input: VolumeSpeedTestInput; output: VolumeSpeedTestOutput }
| { type: 'media.thumbnail.regenerate'; input: RegenerateThumbnailInput; output: RegenerateThumbnailOutput }
| { type: 'media.thumbnail'; input: ThumbnailInput; output: JobReceipt }
| { type: 'locations.rescan'; input: LocationRescanInput; output: LocationRescanOutput }
| { type: 'volumes.add_cloud'; input: VolumeAddCloudInput; output: VolumeAddCloudOutput }
| { type: 'spaces.delete_group'; input: DeleteGroupInput; output: DeleteGroupOutput }
| { type: 'spaces.delete'; input: SpaceDeleteInput; output: SpaceDeleteOutput }
| { type: 'files.copy'; input: FileCopyInput; output: JobReceipt }
| { type: 'volumes.refresh'; input: VolumeRefreshInput; output: VolumeRefreshOutput }
| { type: 'volumes.remove_cloud'; input: VolumeRemoveCloudInput; output: VolumeRemoveCloudOutput }
| { type: 'locations.remove'; input: LocationRemoveInput; output: LocationRemoveOutput }
| { type: 'indexing.start'; input: IndexInput; output: JobReceipt }
| { type: 'media.ocr.extract'; input: ExtractTextInput; output: ExtractTextOutput }
| { type: 'spaces.delete_group'; input: DeleteGroupInput; output: DeleteGroupOutput }
| { type: 'jobs.cancel'; input: JobCancelInput; output: JobCancelOutput }
| { type: 'spaces.delete_item'; input: DeleteItemInput; output: DeleteItemOutput }
;
export type CoreQuery =
{ type: 'network.devices.list'; input: ListPairedDevicesInput; output: ListPairedDevicesOutput }
{ type: 'network.status'; input: NetworkStatusQueryInput; output: NetworkStatus }
| { type: 'models.whisper.list'; input: ListWhisperModelsInput; output: ListWhisperModelsOutput }
| { type: 'network.sync_setup.discover'; input: DiscoverRemoteLibrariesInput; output: DiscoverRemoteLibrariesOutput }
| { type: 'core.status'; input: Empty; output: CoreStatus }
| { type: 'network.pair.status'; input: PairStatusQueryInput; output: PairStatusOutput }
| { type: 'models.whisper.list'; input: ListWhisperModelsInput; output: ListWhisperModelsOutput }
| { type: 'network.status'; input: NetworkStatusQueryInput; output: NetworkStatus }
| { type: 'core.events.list'; input: ListEventsInput; output: ListEventsOutput }
| { type: 'network.devices.list'; input: ListPairedDevicesInput; output: ListPairedDevicesOutput }
| { type: 'libraries.list'; input: ListLibrariesInput; output: [LibraryInfo] }
| { type: 'network.sync_setup.discover'; input: DiscoverRemoteLibrariesInput; output: DiscoverRemoteLibrariesOutput }
;
export type LibraryQuery =
{ type: 'libraries.info'; input: LibraryInfoQueryInput; output: LibraryInfoOutput }
| { type: 'locations.list'; input: LocationsListQueryInput; output: LocationsListOutput }
| { type: 'sync.metrics'; input: GetSyncMetricsInput; output: GetSyncMetricsOutput }
| { type: 'spaces.get'; input: SpaceGetQueryInput; output: SpaceGetOutput }
| { type: 'files.directory_listing'; input: DirectoryListingInput; output: DirectoryListingOutput }
| { type: 'jobs.list'; input: JobListInput; output: JobListOutput }
| { type: 'jobs.info'; input: JobInfoQueryInput; output: JobInfoOutput }
| { type: 'files.media_listing'; input: MediaListingInput; output: MediaListingOutput }
| { type: 'search.files'; input: FileSearchInput; output: FileSearchOutput }
| { type: 'sync.metrics'; input: GetSyncMetricsInput; output: GetSyncMetricsOutput }
| { type: 'volumes.list'; input: VolumeListQueryInput; output: VolumeListOutput }
| { type: 'locations.list'; input: LocationsListQueryInput; output: LocationsListOutput }
| { type: 'test.ping'; input: PingInput; output: PingOutput }
| { type: 'files.by_path'; input: FileByPathQuery; output: File }
| { type: 'spaces.get_layout'; input: SpaceLayoutQueryInput; output: SpaceLayout }
| { type: 'tags.search'; input: SearchTagsInput; output: SearchTagsOutput }
| { type: 'files.unique_to_location'; input: UniqueToLocationInput; output: UniqueToLocationOutput }
| { type: 'volumes.list'; input: VolumeListQueryInput; output: VolumeListOutput }
| { type: 'locations.suggested'; input: SuggestedLocationsQueryInput; output: SuggestedLocationsOutput }
| { type: 'devices.list'; input: ListLibraryDevicesInput; output: [LibraryDeviceInfo] }
| { type: 'spaces.list'; input: SpacesListQueryInput; output: SpacesListOutput }
| { type: 'locations.suggested'; input: SuggestedLocationsQueryInput; output: SuggestedLocationsOutput }
| { type: 'tags.search'; input: SearchTagsInput; output: SearchTagsOutput }
| { type: 'spaces.get'; input: SpaceGetQueryInput; output: SpaceGetOutput }
| { type: 'files.media_listing'; input: MediaListingInput; output: MediaListingOutput }
| { type: 'spaces.get_layout'; input: SpaceLayoutQueryInput; output: SpaceLayout }
| { type: 'jobs.info'; input: JobInfoQueryInput; output: JobInfoOutput }
| { type: 'files.by_id'; input: FileByIdQuery; output: File }
;
@@ -3306,92 +3322,92 @@ export type LibraryQuery =
export const WIRE_METHODS = {
coreActions: {
'network.start': 'action:network.start.input',
'network.device.revoke': 'action:network.device.revoke.input',
'network.stop': 'action:network.stop.input',
'network.spacedrop.send': 'action:network.spacedrop.send.input',
'network.pair.generate': 'action:network.pair.generate.input',
'libraries.delete': 'action:libraries.delete.input',
'network.sync_setup': 'action:network.sync_setup.input',
'models.whisper.delete': 'action:models.whisper.delete.input',
'models.whisper.download': 'action:models.whisper.download.input',
'network.device.revoke': 'action:network.device.revoke.input',
'libraries.delete': 'action:libraries.delete.input',
'network.stop': 'action:network.stop.input',
'network.sync_setup': 'action:network.sync_setup.input',
'libraries.create': 'action:libraries.create.input',
'libraries.open': 'action:libraries.open.input',
'network.pair.generate': 'action:network.pair.generate.input',
'network.spacedrop.send': 'action:network.spacedrop.send.input',
'network.pair.join': 'action:network.pair.join.input',
'network.pair.cancel': 'action:network.pair.cancel.input',
'network.start': 'action:network.start.input',
'libraries.create': 'action:libraries.create.input',
},
libraryActions: {
'spaces.add_group': 'action:spaces.add_group.input',
'spaces.update_group': 'action:spaces.update_group.input',
'locations.remove': 'action:locations.remove.input',
'indexing.verify': 'action:indexing.verify.input',
'spaces.reorder_items': 'action:spaces.reorder_items.input',
'spaces.reorder_groups': 'action:spaces.reorder_groups.input',
'spaces.update': 'action:spaces.update.input',
'volumes.track': 'action:volumes.track.input',
'spaces.create': 'action:spaces.create.input',
'spaces.delete_item': 'action:spaces.delete_item.input',
'media.thumbstrip.generate': 'action:media.thumbstrip.generate.input',
'tags.create': 'action:tags.create.input',
'indexing.start': 'action:indexing.start.input',
'jobs.cancel': 'action:jobs.cancel.input',
'jobs.pause': 'action:jobs.pause.input',
'files.delete': 'action:files.delete.input',
'media.speech.transcribe': 'action:media.speech.transcribe.input',
'volumes.speed_test': 'action:volumes.speed_test.input',
'locations.update': 'action:locations.update.input',
'jobs.resume': 'action:jobs.resume.input',
'spaces.add_item': 'action:spaces.add_item.input',
'media.proxy.generate': 'action:media.proxy.generate.input',
'volumes.add_cloud': 'action:volumes.add_cloud.input',
'locations.add': 'action:locations.add.input',
'locations.triggerJob': 'action:locations.triggerJob.input',
'libraries.export': 'action:libraries.export.input',
'files.copy': 'action:files.copy.input',
'tags.apply': 'action:tags.apply.input',
'jobs.pause': 'action:jobs.pause.input',
'spaces.create': 'action:spaces.create.input',
'libraries.export': 'action:libraries.export.input',
'libraries.rename': 'action:libraries.rename.input',
'jobs.resume': 'action:jobs.resume.input',
'files.delete': 'action:files.delete.input',
'locations.update': 'action:locations.update.input',
'locations.rescan': 'action:locations.rescan.input',
'media.speech.transcribe': 'action:media.speech.transcribe.input',
'spaces.add_item': 'action:spaces.add_item.input',
'spaces.reorder_items': 'action:spaces.reorder_items.input',
'spaces.reorder_groups': 'action:spaces.reorder_groups.input',
'locations.triggerJob': 'action:locations.triggerJob.input',
'spaces.delete': 'action:spaces.delete.input',
'volumes.remove_cloud': 'action:volumes.remove_cloud.input',
'volumes.track': 'action:volumes.track.input',
'spaces.add_group': 'action:spaces.add_group.input',
'spaces.update_group': 'action:spaces.update_group.input',
'indexing.verify': 'action:indexing.verify.input',
'spaces.update': 'action:spaces.update.input',
'volumes.untrack': 'action:volumes.untrack.input',
'volumes.refresh': 'action:volumes.refresh.input',
'media.proxy.generate': 'action:media.proxy.generate.input',
'volumes.speed_test': 'action:volumes.speed_test.input',
'media.thumbnail.regenerate': 'action:media.thumbnail.regenerate.input',
'media.thumbnail': 'action:media.thumbnail.input',
'locations.rescan': 'action:locations.rescan.input',
'volumes.add_cloud': 'action:volumes.add_cloud.input',
'spaces.delete_group': 'action:spaces.delete_group.input',
'spaces.delete': 'action:spaces.delete.input',
'files.copy': 'action:files.copy.input',
'volumes.refresh': 'action:volumes.refresh.input',
'volumes.remove_cloud': 'action:volumes.remove_cloud.input',
'locations.remove': 'action:locations.remove.input',
'indexing.start': 'action:indexing.start.input',
'media.ocr.extract': 'action:media.ocr.extract.input',
'spaces.delete_group': 'action:spaces.delete_group.input',
'jobs.cancel': 'action:jobs.cancel.input',
'spaces.delete_item': 'action:spaces.delete_item.input',
},
coreQueries: {
'network.devices.list': 'query:network.devices.list',
'network.status': 'query:network.status',
'models.whisper.list': 'query:models.whisper.list',
'network.sync_setup.discover': 'query:network.sync_setup.discover',
'core.status': 'query:core.status',
'network.pair.status': 'query:network.pair.status',
'models.whisper.list': 'query:models.whisper.list',
'network.status': 'query:network.status',
'core.events.list': 'query:core.events.list',
'network.devices.list': 'query:network.devices.list',
'libraries.list': 'query:libraries.list',
'network.sync_setup.discover': 'query:network.sync_setup.discover',
},
libraryQueries: {
'libraries.info': 'query:libraries.info',
'locations.list': 'query:locations.list',
'sync.metrics': 'query:sync.metrics',
'spaces.get': 'query:spaces.get',
'files.directory_listing': 'query:files.directory_listing',
'jobs.list': 'query:jobs.list',
'jobs.info': 'query:jobs.info',
'files.media_listing': 'query:files.media_listing',
'search.files': 'query:search.files',
'sync.metrics': 'query:sync.metrics',
'volumes.list': 'query:volumes.list',
'locations.list': 'query:locations.list',
'test.ping': 'query:test.ping',
'files.by_path': 'query:files.by_path',
'spaces.get_layout': 'query:spaces.get_layout',
'tags.search': 'query:tags.search',
'files.unique_to_location': 'query:files.unique_to_location',
'volumes.list': 'query:volumes.list',
'locations.suggested': 'query:locations.suggested',
'devices.list': 'query:devices.list',
'spaces.list': 'query:spaces.list',
'locations.suggested': 'query:locations.suggested',
'tags.search': 'query:tags.search',
'spaces.get': 'query:spaces.get',
'files.media_listing': 'query:files.media_listing',
'spaces.get_layout': 'query:spaces.get_layout',
'jobs.info': 'query:jobs.info',
'files.by_id': 'query:files.by_id',
},
} as const;