@nakanoaas/notion-valibot-schema
v0.0.8
Published
Turn Notion's nested API responses into clean, typed JavaScript values.
Downloads
717
Readme
Notion Valibot Schema
Turn Notion's nested API responses into clean, typed JavaScript values.
This library provides a collection of Valibot schemas specifically designed to handle Notion API objects. It doesn't just validate; it transforms deeply nested Notion properties into simple, usable primitives like string, number, Date, and boolean.
The Problem
When you fetch a page from Notion, properties are deeply nested. To access them type-safely, you end up writing verbose type guards for every single property.
// 😫 The "Native" Way (Boilerplate Hell)
// 1. Get the property
const statusProp = page.properties["Status"];
// 2. Check if it exists and has the correct type
if (statusProp?.type === "status" && statusProp.status) {
// 3. Finally access the value
console.log(statusProp.status.name); // "In Progress"
}
// Repeat this for every property...
const tagsProp = page.properties["Tags"];
if (tagsProp?.type === "multi_select") {
console.log(tagsProp.multi_select.map(t => t.name));
}The Solution
With @nakanoaas/notion-valibot-schema, you get this:
// After parsing
{
Status: "In Progress",
Tags: ["Urgent", "Work"],
DueDate: new Date("2023-12-25")
}No more checking for property.type === 'date', handling null, or digging through 3 layers of objects just to get a string.
Features
- 🧩 Composable: Works seamlessly with standard Valibot schemas (
v.object,v.array, etc.). - ✨ Transformative: Automatically extracts values (e.g.,
RichText[]->string). - 🔒 Type-Safe: Full TypeScript support with inferred types.
- ✅ Well Tested: Backed by a comprehensive test suite covering edge cases.
- 🛠 Comprehensive: Supports complex properties like Rollups, Formulas, and Relations.
Installation
Node.js (npm / pnpm / yarn / bun)
npm install @nakanoaas/notion-valibot-schema valibotpnpm add @nakanoaas/notion-valibot-schema valibotDeno / JSR
deno add @nakanoaas/notion-valibot-schema @valibot/valibotUsage
Basic Example
Here is how to validate and transform a Notion page retrieved from the API.
import * as v from "valibot";
import {
TitleSchema,
RichTextSchema,
StatusSchema,
MultiSelectSchema,
NullableSingleDateSchema,
CheckboxSchema,
} from "@nakanoaas/notion-valibot-schema";
// 1. Define your schema based on your Data Source properties
const TaskPageSchema = v.object({
id: v.string(),
properties: v.object({
// Map "Name" property -> string
Name: TitleSchema,
// Map "Description" property -> string
Description: RichTextSchema,
// Map "Status" property -> "ToDo" | "Doing" | "Done"
Status: StatusSchema(v.picklist(["ToDo", "Doing", "Done"])),
// Map "Tags" -> string[]
Tags: MultiSelectSchema(v.string()),
// Map "Due Date" -> Date | null
DueDate: NullableSingleDateSchema,
// Map "IsUrgent" -> boolean
IsUrgent: CheckboxSchema,
}),
});
// 2. Fetch data from Notion
const page = await notion.pages.retrieve({ page_id: "..." });
// 3. Parse and transform
const task = v.parse(TaskPageSchema, page);
// 4. Use your clean data
console.log(task.properties.Name); // "Buy Milk" (string)
console.log(task.properties.DueDate); // Date object or null
console.log(task.properties.Tags); // ["Personal", "Shopping"] (string[])Handling Lists (Query Results)
To parse the results of a data source query:
const TaskListSchema = v.array(TaskPageSchema);
const { results } = await notion.dataSources.query({ data_source_id: "..." });
const tasks = v.parse(TaskListSchema, results);Schema Reference
📚 For complete API documentation, including all available schemas and types, please visit the JSR Documentation.
| Notion Property | Schema | Transformed Output (Type) |
| :--- | :--- | :--- |
| Text / Title | TitleSchema / RichTextSchema | string |
| Number | NumberSchema / NullableNumberSchema | number / number \| null |
| Checkbox | CheckboxSchema | boolean |
| Select | SelectSchema(schema) | Inferred<schema> |
| Multi-Select | MultiSelectSchema(schema) | Inferred<schema>[] |
| Status | StatusSchema(schema) | Inferred<schema> |
| Date (Single) | SingleDateSchema / NullableSingleDateSchema | Date / Date \| null |
| Date (Range) | RangeDateSchema / NullableRangeDateSchema | { start: Date; end: Date; time_zone: string \| null } / { start: Date; end: Date; time_zone: string \| null } \| null |
| Date (Full) | FullDateSchema / NullableFullDateSchema | { start: Date; end: Date \| null; time_zone: string \| null } / { start: Date; end: Date \| null; time_zone: string \| null } \| null |
| Relation | RelationSchema | string[] (Page IDs) |
| Relation (Single) | SingleRelationSchema | string (Page ID) |
| URL | UrlSchema | string |
| Email | EmailSchema | string |
| Phone | PhoneNumberSchema | string |
| Files | FilesSchema | string[] (URLs) |
| Created/Edited By | CreatedBySchema / LastEditedBySchema | string (User ID) |
| Created/Edited Time| CreatedTimeSchema / LastEditedTimeSchema | Date |
Advanced Schemas
Date Properties
Notion date properties can represent single dates, date ranges, or date ranges with optional end dates. Choose the appropriate schema based on your needs:
Single: Returns just the start date as a
DateobjectSingleDateSchema: Requires start date →DateNullableSingleDateSchema: Allows null →Date | null
Range: Requires both start and end dates
RangeDateSchema: Requires start and end dates →{ start: Date; end: Date; time_zone: string | null }NullableRangeDateSchema: Allows null →{ start: Date; end: Date; time_zone: string | null } | null
Full: Start date required, end date optional
FullDateSchema: Requires start date, optional end date →{ start: Date; end: Date | null; time_zone: string | null }NullableFullDateSchema: Allows null →{ start: Date; end: Date | null; time_zone: string | null } | null
import {
SingleDateSchema,
NullableSingleDateSchema,
RangeDateSchema,
FullDateSchema,
} from "@nakanoaas/notion-valibot-schema";
const MySchema = v.object({
// Single date (start date only)
DueDate: NullableSingleDateSchema,
// Date range (both start and end required)
EventPeriod: RangeDateSchema,
// Full date range (end date optional)
ProjectTimeline: FullDateSchema,
});Formulas
Formulas in Notion can return different types (string, number, boolean, date). Use FormulaSchema with a specific inner schema to handle this.
import { FormulaSchema, RichTextSchema } from "@nakanoaas/notion-valibot-schema";
const MySchema = v.object({
// If your formula returns text
MyFormula: FormulaSchema(RichTextSchema),
});Rollups
Rollups are powerful but complex. We provide helpers for common rollup types.
import {
RollupNumberSchema,
RollupDateSchema,
RollupArraySchema
} from "@nakanoaas/notion-valibot-schema";
const MySchema = v.object({
// Sum/Average rollup (returns number)
TotalCost: RollupNumberSchema,
// Date rollup (returns Date)
LatestMeeting: RollupDateSchema,
// Array rollup (e.g., pulling tags from related items)
AllTags: RollupArraySchema(v.string())
});License
MIT © Nakano as a Service
