Migrated read APIs to Nitro
This commit is contained in:
1 parent
eb4e9f0700
commit
ee5809a489
26 files changed
+558
No files matched your search
@@ -0,0 +1,16 @@
|
||||
import { getRouterParam } from "h3"
|
||||
import { Album } from "../../models/album"
|
||||
import { requireAuthenticatedUser } from "../../utils/auth"
|
||||
import { parseMongoId, validationResponse } from "../../utils/api-validation"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
const parsedId = parseMongoId(getRouterParam(event, "id"))
|
||||
if ("error" in parsedId) return validationResponse(event, parsedId.error)
|
||||
|
||||
return Album.findOne({ _id: parsedId.value })
|
||||
.populate("artists")
|
||||
.populate("genre")
|
||||
.exec()
|
||||
})
|
||||
@@ -0,0 +1,24 @@
|
||||
import { getQuery, getRouterParam } from "h3"
|
||||
import { Track } from "../../../models/track"
|
||||
import { requireAuthenticatedUser } from "../../../utils/auth"
|
||||
import { parseMongoId, parseNumber, validationResponse } from "../../../utils/api-validation"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
const parsedId = parseMongoId(getRouterParam(event, "id"))
|
||||
if ("error" in parsedId) return validationResponse(event, parsedId.error)
|
||||
|
||||
const query = getQuery(event)
|
||||
const limit = parseNumber(query.limit, 9, 1)
|
||||
if ("error" in limit) return validationResponse(event, limit.error)
|
||||
const skip = parseNumber(query.skip, 0, 0)
|
||||
if ("error" in skip) return validationResponse(event, skip.error)
|
||||
|
||||
return Track.find({ album: parsedId.value })
|
||||
.limit(limit.value || 9)
|
||||
.skip(skip.value || 0)
|
||||
.populate("artists")
|
||||
.populate({ path: "album", select: "-artists -genre" })
|
||||
.exec()
|
||||
})
|
||||
@@ -0,0 +1,16 @@
|
||||
import { getQuery } from "h3"
|
||||
import { Album } from "../../models/album"
|
||||
import { requireAuthenticatedUser } from "../../utils/auth"
|
||||
import { parseMongoIds, validationResponse } from "../../utils/api-validation"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
const parsedIds = parseMongoIds(getQuery(event).ids)
|
||||
if ("error" in parsedIds) return validationResponse(event, parsedIds.error)
|
||||
|
||||
return Album.find({ _id: { $in: parsedIds.value } })
|
||||
.populate("artists")
|
||||
.populate("genre")
|
||||
.exec()
|
||||
})
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Album } from "../../models/album"
|
||||
import { requireAuthenticatedUser } from "../../utils/auth"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
return Album.find({}).populate("artists").populate("genre")
|
||||
})
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Artist } from "../../models/artist"
|
||||
import { requireAuthenticatedUser } from "../../utils/auth"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
return Artist.find({})
|
||||
})
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Genre } from "../../models/genre"
|
||||
import { requireAuthenticatedUser } from "../../utils/auth"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
return Genre.find({})
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Track } from "../../models/track"
|
||||
import { requireAuthenticatedUser } from "../../utils/auth"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
return Track.find({})
|
||||
.populate({
|
||||
path: "album",
|
||||
select: "-artists",
|
||||
populate: { path: "genre" },
|
||||
})
|
||||
.populate("artists")
|
||||
})
|
||||
@@ -0,0 +1,13 @@
|
||||
import { getRouterParam } from "h3"
|
||||
import { Artist } from "../../models/artist"
|
||||
import { requireAuthenticatedUser } from "../../utils/auth"
|
||||
import { parseMongoId, validationResponse } from "../../utils/api-validation"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
const parsedId = parseMongoId(getRouterParam(event, "id"))
|
||||
if ("error" in parsedId) return validationResponse(event, parsedId.error)
|
||||
|
||||
return Artist.findOne({ _id: parsedId.value }).exec()
|
||||
})
|
||||
@@ -0,0 +1,24 @@
|
||||
import { getQuery, getRouterParam } from "h3"
|
||||
import { Album } from "../../../models/album"
|
||||
import { requireAuthenticatedUser } from "../../../utils/auth"
|
||||
import { parseMongoId, parseNumber, validationResponse } from "../../../utils/api-validation"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
const parsedId = parseMongoId(getRouterParam(event, "id"))
|
||||
if ("error" in parsedId) return validationResponse(event, parsedId.error)
|
||||
|
||||
const query = getQuery(event)
|
||||
const limit = parseNumber(query.limit, 9, 1)
|
||||
if ("error" in limit) return validationResponse(event, limit.error)
|
||||
const skip = parseNumber(query.skip, 0, 0)
|
||||
if ("error" in skip) return validationResponse(event, skip.error)
|
||||
|
||||
return Album.find({ artists: parsedId.value })
|
||||
.limit(limit.value || 9)
|
||||
.skip(skip.value || 0)
|
||||
.populate("genre")
|
||||
.populate("artists")
|
||||
.exec()
|
||||
})
|
||||
@@ -0,0 +1,24 @@
|
||||
import { getQuery, getRouterParam } from "h3"
|
||||
import { Track } from "../../../models/track"
|
||||
import { requireAuthenticatedUser } from "../../../utils/auth"
|
||||
import { parseMongoId, parseNumber, validationResponse } from "../../../utils/api-validation"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
const parsedId = parseMongoId(getRouterParam(event, "id"))
|
||||
if ("error" in parsedId) return validationResponse(event, parsedId.error)
|
||||
|
||||
const query = getQuery(event)
|
||||
const limit = parseNumber(query.limit, 9, 1)
|
||||
if ("error" in limit) return validationResponse(event, limit.error)
|
||||
const skip = parseNumber(query.skip, 0, 0)
|
||||
if ("error" in skip) return validationResponse(event, skip.error)
|
||||
|
||||
return Track.find({ artists: parsedId.value })
|
||||
.limit(limit.value || 9)
|
||||
.skip(skip.value || 0)
|
||||
.populate({ path: "album", select: "-artists" })
|
||||
.populate("artists")
|
||||
.exec()
|
||||
})
|
||||
@@ -0,0 +1,13 @@
|
||||
import { getQuery } from "h3"
|
||||
import { Artist } from "../../models/artist"
|
||||
import { requireAuthenticatedUser } from "../../utils/auth"
|
||||
import { parseMongoIds, validationResponse } from "../../utils/api-validation"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
const parsedIds = parseMongoIds(getQuery(event).ids)
|
||||
if ("error" in parsedIds) return validationResponse(event, parsedIds.error)
|
||||
|
||||
return Artist.find({ _id: { $in: parsedIds.value } }).exec()
|
||||
})
|
||||
@@ -0,0 +1,31 @@
|
||||
import mongoose, { type PipelineStage } from "mongoose"
|
||||
import { Album } from "../../../models/album"
|
||||
import { parseMongoId, parseNumber, validationResponse } from "../../../utils/api-validation"
|
||||
import { requireAuthenticatedUser } from "../../../utils/auth"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
const id = parseMongoId(getRouterParam(event, "id"))
|
||||
if ("error" in id) return validationResponse(event, id.error)
|
||||
|
||||
const { limit: rawLimit } = getQuery(event)
|
||||
const limit = parseNumber(rawLimit, 10, 1)
|
||||
if ("error" in limit) return validationResponse(event, limit.error)
|
||||
|
||||
const pipeline: PipelineStage[] = [
|
||||
{ $match: { genre: new mongoose.Types.ObjectId(id.value) } },
|
||||
{ $sample: { size: limit.value || 10 } },
|
||||
{
|
||||
$lookup: {
|
||||
from: "artists",
|
||||
localField: "artists",
|
||||
foreignField: "_id",
|
||||
as: "artists",
|
||||
},
|
||||
},
|
||||
{ $unset: "genre" },
|
||||
]
|
||||
|
||||
return Album.aggregate(pipeline)
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Genre } from "../../models/genre"
|
||||
import { parseNumber, validationResponse } from "../../utils/api-validation"
|
||||
import { requireAuthenticatedUser } from "../../utils/auth"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
const { limit: rawLimit } = getQuery(event)
|
||||
const limit = parseNumber(rawLimit, 10, 1)
|
||||
if ("error" in limit) return validationResponse(event, limit.error)
|
||||
|
||||
const genres = await Genre.aggregate([{ $sample: { size: limit.value || 10 } }])
|
||||
return genres
|
||||
})
|
||||
@@ -0,0 +1,40 @@
|
||||
import mongoose, { type PipelineStage } from "mongoose"
|
||||
import { Track } from "../../../models/track"
|
||||
import { parseMongoId, parseNumber, validationResponse } from "../../../utils/api-validation"
|
||||
import { requireAuthenticatedUser } from "../../../utils/auth"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
const id = parseMongoId(getRouterParam(event, "id"))
|
||||
if ("error" in id) return validationResponse(event, id.error)
|
||||
|
||||
const { limit: rawLimit } = getQuery(event)
|
||||
const limit = parseNumber(rawLimit, 10, 1)
|
||||
if ("error" in limit) return validationResponse(event, limit.error)
|
||||
|
||||
const pipeline: PipelineStage[] = [
|
||||
{
|
||||
$lookup: {
|
||||
from: "albums",
|
||||
localField: "album",
|
||||
foreignField: "_id",
|
||||
as: "album",
|
||||
},
|
||||
},
|
||||
{ $unwind: "$album" },
|
||||
{
|
||||
$lookup: {
|
||||
from: "artists",
|
||||
localField: "artists",
|
||||
foreignField: "_id",
|
||||
as: "artists",
|
||||
},
|
||||
},
|
||||
{ $match: { "album.genre": new mongoose.Types.ObjectId(id.value) } },
|
||||
{ $sample: { size: limit.value || 10 } },
|
||||
{ $unset: "album.artists" },
|
||||
]
|
||||
|
||||
return Track.aggregate(pipeline)
|
||||
})
|
||||
@@ -0,0 +1,95 @@
|
||||
import Fuse from "fuse.js"
|
||||
import { Album } from "../models/album"
|
||||
import { Artist } from "../models/artist"
|
||||
import { Track } from "../models/track"
|
||||
import {
|
||||
parseNumber,
|
||||
parseQueryString,
|
||||
validationResponse,
|
||||
} from "../utils/api-validation"
|
||||
import { requireAuthenticatedUser } from "../utils/auth"
|
||||
|
||||
const searchTypes = ["track", "album", "artist", "default"] as const
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
const query = getQuery(event)
|
||||
const q = parseQueryString(query.q)
|
||||
if ("error" in q) return validationResponse(event, q.error)
|
||||
|
||||
let type = "default"
|
||||
if (query.type !== undefined) {
|
||||
const parsedType = parseQueryString(query.type)
|
||||
if ("error" in parsedType) return validationResponse(event, parsedType.error)
|
||||
if (!searchTypes.includes(parsedType.value as (typeof searchTypes)[number])) {
|
||||
return validationResponse(
|
||||
event,
|
||||
`Invalid enum value. Expected 'track' | 'album' | 'artist' | 'default', received '${parsedType.value}'`,
|
||||
)
|
||||
}
|
||||
type = parsedType.value
|
||||
}
|
||||
|
||||
const parsedLimit = parseNumber(query.limit, 9, 1)
|
||||
if ("error" in parsedLimit) return validationResponse(event, parsedLimit.error)
|
||||
const limit = parsedLimit.value
|
||||
|
||||
let results: { tracks: any[]; albums: any[]; artists: any[] } = {
|
||||
tracks: [],
|
||||
albums: [],
|
||||
artists: [],
|
||||
}
|
||||
|
||||
if (type === "track" || type === "default") {
|
||||
const rawTracks = await Track.find({})
|
||||
.populate(["album", "artists"])
|
||||
.lean()
|
||||
|
||||
const fuse = new Fuse(rawTracks, {
|
||||
keys: ["name", "lyrics.text"],
|
||||
threshold: 0.3,
|
||||
distance: 100,
|
||||
ignoreLocation: true,
|
||||
})
|
||||
|
||||
results.tracks = fuse.search(q.value).slice(0, limit).map((result) => result.item)
|
||||
}
|
||||
|
||||
if (type === "album" || type === "default") {
|
||||
const rawAlbums = await Album.find({})
|
||||
.populate(["artists", "genre"])
|
||||
.lean()
|
||||
|
||||
const fuse = new Fuse(rawAlbums, {
|
||||
keys: ["name"],
|
||||
threshold: 0.3,
|
||||
distance: 100,
|
||||
ignoreLocation: true,
|
||||
})
|
||||
|
||||
results.albums = fuse.search(q.value).slice(0, limit).map((result) => result.item)
|
||||
}
|
||||
|
||||
if (type === "artist" || type === "default") {
|
||||
const rawArtists = await Artist.find({}).lean()
|
||||
|
||||
const fuse = new Fuse(rawArtists, {
|
||||
keys: ["name"],
|
||||
threshold: 0.3,
|
||||
distance: 100,
|
||||
ignoreLocation: true,
|
||||
})
|
||||
|
||||
results.artists = fuse.search(q.value).slice(0, limit).map((result) => result.item)
|
||||
}
|
||||
|
||||
// Keep the original API's split allocation, including when type selects one category.
|
||||
results = {
|
||||
tracks: results.tracks.slice(0, Math.ceil(limit / 3)),
|
||||
albums: results.albums.slice(0, Math.floor(limit / 3)),
|
||||
artists: results.artists.slice(0, Math.floor(limit / 3)),
|
||||
}
|
||||
|
||||
return results
|
||||
})
|
||||
@@ -0,0 +1,20 @@
|
||||
import { getQuery } from "h3"
|
||||
import { Track } from "../models/track"
|
||||
import { requireAuthenticatedUser } from "../utils/auth"
|
||||
import { parseMongoIds, validationResponse } from "../utils/api-validation"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
const parsedIds = parseMongoIds(getQuery(event).ids)
|
||||
if ("error" in parsedIds) return validationResponse(event, parsedIds.error)
|
||||
|
||||
return Track.find({ _id: { $in: parsedIds.value } })
|
||||
.populate({
|
||||
path: "album",
|
||||
select: "-artists",
|
||||
populate: { path: "genre" },
|
||||
})
|
||||
.populate("artists")
|
||||
.exec()
|
||||
})
|
||||
@@ -0,0 +1,20 @@
|
||||
import { getRouterParam } from "h3"
|
||||
import { Track } from "../../models/track"
|
||||
import { requireAuthenticatedUser } from "../../utils/auth"
|
||||
import { parseMongoId, validationResponse } from "../../utils/api-validation"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
const parsedId = parseMongoId(getRouterParam(event, "id"))
|
||||
if ("error" in parsedId) return validationResponse(event, parsedId.error)
|
||||
|
||||
return Track.findOne({ _id: parsedId.value })
|
||||
.populate({
|
||||
path: "album",
|
||||
select: "-artists",
|
||||
populate: { path: "genre" },
|
||||
})
|
||||
.populate("artists")
|
||||
.exec()
|
||||
})
|
||||
@@ -0,0 +1,16 @@
|
||||
import { getRouterParam } from "h3"
|
||||
import { Track } from "../../../models/track"
|
||||
import { requireAuthenticatedUser } from "../../../utils/auth"
|
||||
import { parseMongoId, validationResponse } from "../../../utils/api-validation"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAuthenticatedUser(event)
|
||||
|
||||
const parsedId = parseMongoId(getRouterParam(event, "id"))
|
||||
if ("error" in parsedId) return validationResponse(event, parsedId.error)
|
||||
|
||||
const track = await Track.findOne({ _id: parsedId.value }).select("lyrics").exec()
|
||||
if (!track) return {}
|
||||
|
||||
return track.lyrics
|
||||
})
|
||||
@@ -0,0 +1,5 @@
|
||||
import { requireAuthenticatedUser } from "../../utils/auth"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
return await requireAuthenticatedUser(event)
|
||||
})
|
||||
@@ -0,0 +1,15 @@
|
||||
import { User } from "../../models/user"
|
||||
import { requireAuthenticatedUser } from "../../utils/auth"
|
||||
import { setResponseStatus } from "h3"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const authenticatedUser = await requireAuthenticatedUser(event)
|
||||
const user = await User.findById(authenticatedUser._id).populate("savedTracks")
|
||||
|
||||
if (!user) {
|
||||
setResponseStatus(event, 404)
|
||||
return { message: "User not found" }
|
||||
}
|
||||
|
||||
return user.savedTracks
|
||||
})
|
||||
@@ -0,0 +1,26 @@
|
||||
import { getQuery, setResponseStatus } from "h3"
|
||||
import mongoose, { type ObjectId } from "mongoose"
|
||||
import { User } from "../../models/user"
|
||||
import { requireAuthenticatedUser } from "../../utils/auth"
|
||||
import { parseMongoId, validationResponse } from "../../utils/api-validation"
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const authenticatedUser = await requireAuthenticatedUser(event)
|
||||
const parsedId = parseMongoId(getQuery(event).id)
|
||||
if ("error" in parsedId) return validationResponse(event, parsedId.error)
|
||||
|
||||
const user = await User.findById(authenticatedUser._id)
|
||||
if (!user) {
|
||||
setResponseStatus(event, 404)
|
||||
return { message: "User not found" }
|
||||
}
|
||||
|
||||
// Preserve the legacy comparison behavior and empty-object response.
|
||||
if ((user.savedTracks as ObjectId[]).includes(parsedId.value as unknown as ObjectId)) {
|
||||
return {}
|
||||
}
|
||||
|
||||
user.savedTracks.push(new mongoose.Types.ObjectId(parsedId.value))
|
||||
await user.save()
|
||||
return {}
|
||||
})
|
||||
@@ -0,0 +1,15 @@
|
||||
import mongoose, { Schema, type Model } from "mongoose"
|
||||
|
||||
const albumSchema = new Schema({
|
||||
name: { type: String, required: true },
|
||||
artists: {
|
||||
type: [{ type: Schema.Types.ObjectId, ref: "Artist" }],
|
||||
required: true,
|
||||
},
|
||||
file: { type: String, required: true },
|
||||
genre: { type: Schema.Types.ObjectId, ref: "Genre", required: true },
|
||||
})
|
||||
|
||||
export const Album =
|
||||
(mongoose.models.Album as Model<any> | undefined) ??
|
||||
(mongoose.model<any>("Album", albumSchema) as Model<any>)
|
||||
@@ -0,0 +1,10 @@
|
||||
import mongoose, { Schema, type Model } from "mongoose"
|
||||
|
||||
const artistSchema = new Schema({
|
||||
name: { type: String, required: true },
|
||||
file: { type: String, required: true },
|
||||
})
|
||||
|
||||
export const Artist =
|
||||
(mongoose.models.Artist as Model<any> | undefined) ??
|
||||
(mongoose.model<any>("Artist", artistSchema) as Model<any>)
|
||||
@@ -0,0 +1,9 @@
|
||||
import mongoose, { Schema, type Model } from "mongoose"
|
||||
|
||||
const genreSchema = new Schema({
|
||||
name: { type: String, required: true, unique: true },
|
||||
})
|
||||
|
||||
export const Genre =
|
||||
(mongoose.models.Genre as Model<any> | undefined) ??
|
||||
(mongoose.model<any>("Genre", genreSchema) as Model<any>)
|
||||
@@ -0,0 +1,22 @@
|
||||
import mongoose, { Schema, type Model } from "mongoose"
|
||||
|
||||
const trackSchema = new Schema({
|
||||
name: { type: String, required: true },
|
||||
album: { type: Schema.Types.ObjectId, ref: "Album", required: true },
|
||||
artists: {
|
||||
type: [{ type: Schema.Types.ObjectId, ref: "Artist" }],
|
||||
required: true,
|
||||
},
|
||||
fileDir: { type: String, required: true },
|
||||
durationInSeconds: { type: Number, required: true },
|
||||
lyrics: {
|
||||
type: {
|
||||
synced: { type: Boolean, required: true },
|
||||
text: { type: String, required: true },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export const Track =
|
||||
(mongoose.models.Track as Model<any> | undefined) ??
|
||||
(mongoose.model<any>("Track", trackSchema) as Model<any>)
|
||||
@@ -0,0 +1,52 @@
|
||||
import mongoose from "mongoose"
|
||||
import { setResponseStatus, type H3Event } from "h3"
|
||||
|
||||
export type ParseResult<T> = { value: T } | { error: string }
|
||||
|
||||
export function parseMongoId(value: unknown): ParseResult<string> {
|
||||
if (typeof value !== "string" || !mongoose.isValidObjectId(value)) {
|
||||
return { error: "Invalid id" }
|
||||
}
|
||||
return { value }
|
||||
}
|
||||
|
||||
export function parseMongoIds(value: unknown): ParseResult<string[]> {
|
||||
if (typeof value !== "string" && !Array.isArray(value)) {
|
||||
return { error: "Required" }
|
||||
}
|
||||
|
||||
const values = Array.isArray(value) ? value : [value]
|
||||
const ids: string[] = []
|
||||
for (const item of values) {
|
||||
const parsed = parseMongoId(item)
|
||||
if ("error" in parsed) return parsed
|
||||
ids.push(parsed.value)
|
||||
}
|
||||
return { value: ids }
|
||||
}
|
||||
|
||||
export function parseNumber(
|
||||
value: unknown,
|
||||
defaultValue: number,
|
||||
minimum: number,
|
||||
): ParseResult<number> {
|
||||
if (value === undefined) return { value: defaultValue }
|
||||
|
||||
const parsed = Number(value)
|
||||
if (Number.isNaN(parsed)) return { error: "Expected number, received nan" }
|
||||
if (parsed < minimum) {
|
||||
return { error: `Number must be greater than or equal to ${minimum}` }
|
||||
}
|
||||
return { value: parsed }
|
||||
}
|
||||
|
||||
export function parseQueryString(value: unknown): ParseResult<string> {
|
||||
if (value === undefined) return { error: "Required" }
|
||||
if (typeof value !== "string") return { error: "Expected string, received array" }
|
||||
return { value }
|
||||
}
|
||||
|
||||
export function validationResponse(event: H3Event, message: string) {
|
||||
setResponseStatus(event, 400)
|
||||
return { message }
|
||||
}
|
||||
Reference in new issue
Block a user