Server
Use the same schema in Server Components and Server Actions with @virastack/mask/server.
Server entry
The root entry (@virastack/mask) ships the hook, so it carries "use client". In Server Components, Server Actions and shared schema files use @virastack/mask/server: it has createMask, definePreset, the validators, toMinorUnits and parseMasked.
// lib/checkout-masks.ts — no "use client"
import type { MaskSchema } from "@virastack/mask/server"
export const checkoutMasks = {
phone: { preset: "phone", country: "TR" },
card: "card",
cvv: { preset: "cvv", from: "card" },
price: { preset: "currency", from: "currency" },
} as const satisfies MaskSchemaimport { createMask } from "@virastack/mask/server"
const phone = createMask({ preset: "phone", country: "TR" })
export default async function Customers() {
const customers = await getCustomers()
return customers.map((c) => <p key={c.id}>{phone.format(c.phone)}</p>) // (555) 123 45 67
}Server Action
parseMasked takes FormData, URLSearchParams or a plain object. It parses masked text (when the form posts without JavaScript) or raw values, validates them and turns names like address.zip into nested objects.
"use server"
import { parseMasked } from "@virastack/mask/server"
import { checkoutMasks } from "@/lib/checkout-masks"
export async function checkout(formData: FormData) {
const result = parseMasked(checkoutMasks, formData)
if (!result.success) return { errors: result.errors } // { phone: "phone.incomplete" }
// result.data: { phone: "5551234567", card: "4111…", price: "1234.56", currency: "TRY" }
}Standard Schema
Pass any Standard Schema (Zod, Valibot, ArkType…) as the third argument. The package doesn't depend on them; it only uses the shared interface. With a schema the result is a Promise.
import { z } from "zod"
const schema = z.object({
phone: z.string().length(10),
price: z.string().transform(Number),
currency: z.enum(["TRY", "USD"]),
})
const result = await parseMasked(checkoutMasks, formData, schema)
// masks are parsed and validated first, then the schema runs
// result.data → z.output<typeof schema>