@keithce/astro-notion-db
v2.9.0
Published
TypeScript library for working with astrological events in Notion database
Maintainers
Readme
Astro Notion Database Library
A comprehensive TypeScript library for working with astrological events stored in a Notion database. Provides strict typing, parsing utilities, filtering capabilities, and page decorators that exclusively work with official Notion API data.
Features
- Strict Notion API Adherence: Only processes data directly provided by the official Notion API
- Type Safety: Full TypeScript support with strict typing for all Notion API structures
- Page Decorators: Self-contained pages with computed properties based on Notion API data
- Flexible Filtering: Query and filter events with a fluent API
- Timeframe Helpers: Built-in functions for retrieving events by standard time periods
- Validation: Comprehensive validation for data integrity
- Zero Dependencies: Lightweight library with no external runtime dependencies
Notion API Strict Adherence
This library exclusively processes, manipulates, and represents data elements as structured and provided by the official Notion API for a single Notion page. It does not introduce, infer, or utilize any additional data sources, metadata, or contextual information beyond what the Notion API explicitly returns.
Key Principles
- Direct API Mapping: All types and interfaces directly correspond to Notion API specifications
- No Inferred Data: No computed or derived data that isn't based on actual API responses
- Property Preservation: All Notion API properties are preserved exactly as provided
- Type Safety: Strong typing ensures only valid Notion API data structures are used
Installation
npm install @keithce/astro-notion-dbBasic Usage
Parsing Notion API Pages
import { parseAstroEventPage, parseAstroEventPages } from '@keithce/astro-notion-db';
// Parse a raw Notion API page response
const page = parseAstroEventPage(notionApiPage);
// Access core Notion API properties
console.log(page.id); // "example-event-123"
console.log(page.url); // "https://notion.so/example-event-123"
console.log(page.created_time); // "2024-01-15T10:00:00.000Z"
console.log(page.archived); // false
console.log(page.in_trash); // false
// Access Notion API metadata
console.log(page.icon?.emoji); // "🌙"
console.log(page.parent.type); // "database_id"
console.log(page.parent.database_id); // "database-123"Working with Notion API Properties
// Access computed properties based on Notion API data
console.log(page.displayTitle); // "Mercury Retrograde in Pisces"
console.log(page.displayDate); // "Feb 15 - Mar 10, 2024"
console.log(page.isActive); // true/false
// Get astrological summary from Notion API data
const summary = page.getAstrologicalSummary();
// "Planets/Events: Mercury | Zodiac Signs: Pisces | Event Type: Mercury Course | Date: Feb 15 - Mar 10, 2024"
// Direct property access using Notion API property IDs
const nameValue = page.getPropertyValue('title');
const signsValue = page.getPropertyValue('HC%3Fx');
const planetsValue = page.getPropertyValue('LHB%3E');
const eventTypeValue = page.getPropertyValue('kly%5E');
const dateValue = page.getPropertyValue('qegM');
// Get formatted display values
const nameDisplay = page.getPropertyDisplayValue('title');
const signsDisplay = page.getPropertyDisplayValue('HC%3Fx');Complete Working Examples
Example 1: Parsing Notion API Database Query Results
import { parseAstroEventPage, parseAstroEventPages } from '@keithce/astro-notion-db';
import type { NotionPage, NotionClientDatabaseResponse } from '@keithce/astro-notion-db';
// Example Notion API response structure
const exampleNotionResponse: NotionClientDatabaseResponse = {
object: "list",
results: [
{
object: "page",
id: "229513a9-eab9-811d-b8cf-de6b0fda0d65",
created_time: "2025-07-07T22:28:00.000Z",
last_edited_time: "2025-07-11T18:49:00.000Z",
created_by: {
object: "user",
id: "873887d4-7cf1-410a-b7a2-efd659a420f7"
},
last_edited_by: {
object: "user",
id: "873887d4-7cf1-410a-b7a2-efd659a420f7"
},
cover: null,
icon: {
type: "emoji",
emoji: "🌞"
},
parent: {
type: "database_id",
database_id: "214513a9-eab9-80da-b8ea-f1d8e65cea6e"
},
archived: false,
in_trash: false,
properties: {
"Sign the Planet is in": {
id: "HC%3Fx",
type: "multi_select",
multi_select: [
{
id: "d4e6ca88-9ae9-4240-aa79-40910ad5b85c",
name: "Virgo",
color: "green"
}
]
},
"Planet/Event": {
id: "LHB%3E",
type: "multi_select",
multi_select: [
{
id: "d47a4b6c-b98e-479a-a0ce-7a512374c754",
name: "Sun",
color: "yellow"
},
{
id: "8cb30a1f-273c-4354-8e34-60e2b8138b96",
name: "Where Planets Are (Range)",
color: "blue"
}
]
},
"Event Type (Notification)": {
id: "kly%5E",
type: "select",
select: {
id: "db79aa9e-aa73-4309-b97a-98aaf09beb8a",
name: "No Notification (range)",
color: "brown"
}
},
"Date Range": {
id: "qegM",
type: "date",
date: {
start: "2025-09-16",
end: "2025-10-17",
time_zone: null
}
},
"Name": {
id: "title",
type: "title",
title: [
{
type: "text",
text: {
content: "Sun is in Virgo",
link: null
},
annotations: {
bold: false,
italic: false,
strikethrough: false,
underline: false,
code: false,
color: "default"
},
plain_text: "Sun is in Virgo",
href: null
}
]
}
},
url: "https://www.notion.so/Sun-is-in-Virgo-229513a9eab9811db8cfde6b0fda0d65",
public_url: null
}
],
has_more: false
};
// Parse a complete Notion API database query response
function parseNotionDatabaseResponse(response: typeof exampleNotionResponse) {
console.log('Parsing Notion API database response...\n');
const parsedPages = response.results.map((rawPage: NotionPage, index: number) => {
try {
console.log(`Processing page ${index + 1}: ${rawPage.id}`);
// Parse the individual page
const parsedPage = parseAstroEventPage(rawPage as NotionPage);
return {
success: true,
page: parsedPage,
error: null
};
} catch (error) {
console.error(`Failed to parse page ${index + 1}:`, error);
return {
success: false,
page: null,
error: error instanceof Error ? error.message : String(error)
};
}
});
// Filter successful parses
const successfulPages = parsedPages.filter(result => result.success);
const failedPages = parsedPages.filter(result => !result.success);
console.log(`\nParsing Results:`);
console.log(`✅ Successfully parsed: ${successfulPages.length} pages`);
console.log(`❌ Failed to parse: ${failedPages.length} pages`);
if (failedPages.length > 0) {
console.log('\nFailed pages:');
failedPages.forEach((result, index) => {
console.log(` ${index + 1}. Error: ${result.error}`);
});
}
return {
totalPages: response.results.length,
successfulPages: successfulPages.map(result => result.page),
failedPages,
parsedPages
};
}
// Example usage
const result = parseNotionDatabaseResponse(exampleNotionResponse);Example 2: Standardized Parsing with Error Handling
// Example usage of the new standardized parseAstroEventPages function
function demonstrateStandardizedParsing() {
console.log('=== Standardized Parsing Demo ===\n');
// Example 1: Valid response
console.log('1. Parsing valid Notion client response:');
const validResult = parseAstroEventPages(exampleNotionResponse);
console.log(`Status: ${validResult.status}`);
console.log(`Message: ${validResult.message}`);
console.log(`Data: ${validResult.data ? `${validResult.data.length} pages parsed` : 'null'}`);
console.log();
// Example 2: Invalid response structure
console.log('2. Parsing invalid response structure:');
const invalidResponse = { object: 'invalid' } as unknown as NotionClientDatabaseResponse;
const invalidResult = parseAstroEventPages(invalidResponse);
console.log(`Status: ${invalidResult.status}`);
console.log(`Message: ${invalidResult.message}`);
console.log(`Data: ${invalidResult.data ? 'present' : 'null'}`);
console.log();
// Example 3: Empty results
console.log('3. Parsing empty results:');
const emptyResponse: NotionClientDatabaseResponse = {
object: 'list',
results: [],
has_more: false
};
const emptyResult = parseAstroEventPages(emptyResponse);
console.log(`Status: ${emptyResult.status}`);
console.log(`Message: ${emptyResult.message}`);
console.log(`Data: ${emptyResult.data ? `${emptyResult.data.length} pages` : 'null'}`);
console.log();
return {
validResult,
invalidResult,
emptyResult
};
}Example 3: Displaying Astrological Event Information
// Example usage: Parse and display astrological event information
function displayAstroEventInfo(parsedPage: ReturnType<typeof parseAstroEventPage>) {
console.log('\n=== Astrological Event Information ===');
console.log(`Title: ${parsedPage.displayTitle}`);
console.log(`Date Range: ${parsedPage.displayDate}`);
console.log(`Currently Active: ${parsedPage.isActive ? 'Yes' : 'No'}`);
console.log(`Summary: ${parsedPage.getAstrologicalSummary()}`);
console.log('\nDetailed Properties:');
console.log(`- Event Name: ${parsedPage.properties.name.value}`);
console.log(`- Zodiac Signs: ${parsedPage.properties.signThePlanetIsIn.value.join(', ')}`);
console.log(`- Planets/Events: ${parsedPage.properties.planetEvent.value.join(', ')}`);
console.log(`- Notification Type: ${parsedPage.properties.eventTypeNotification.value || 'None'}`);
if (parsedPage.properties.dateRange.value) {
const { start, end, time_zone } = parsedPage.properties.dateRange.value;
console.log(`- Start Date: ${start.toISOString().split('T')[0]}`);
if (end) {
console.log(`- End Date: ${end.toISOString().split('T')[0]}`);
}
if (time_zone) {
console.log(`- Time Zone: ${time_zone}`);
}
}
console.log('\nRaw Notion API Properties Available:');
// Get all property names from the raw page properties
const propertyNames = Object.keys(parsedPage.getPropertyValue('') || {});
propertyNames.forEach(propName => {
const displayValue = parsedPage.getPropertyDisplayValue(propName);
console.log(` - ${propName}: ${displayValue}`);
});
}
// Use the parsed data
if (result.successfulPages.length > 0) {
displayAstroEventInfo(result.successfulPages[0]!);
}Timeframe Helper Functions
The library provides convenient helper functions to retrieve events based on standard time periods:
Basic Timeframe Functions
import {
getEventsToday,
getEventsThisWeek,
getEventsNextWeek,
getEventsThisMonth,
getEventsNextMonth,
groupEventsByMonth,
getEventsInDateRange,
} from '@keithce/astro-notion-db';
// Parse multiple Notion API pages
const events = notionApiPages.map(page => parseAstroEventPage(page));
// Get events happening today
const todayEvents = getEventsToday(events);
console.log(`Events today: ${todayEvents.length}`);
// Get events happening this week (Monday to Sunday)
const thisWeekEvents = getEventsThisWeek(events);
console.log(`Events this week: ${thisWeekEvents.length}`);
// Get events happening next week
const nextWeekEvents = getEventsNextWeek(events);
console.log(`Events next week: ${nextWeekEvents.length}`);
// Get events happening this month
const thisMonthEvents = getEventsThisMonth(events);
console.log(`Events this month: ${thisMonthEvents.length}`);
// Get events happening next month
const nextMonthEvents = getEventsNextMonth(events);
console.log(`Events next month: ${nextMonthEvents.length}`);Advanced Timeframe Operations
// Group events by month for easy organization
const eventsByMonth = groupEventsByMonth(events);
for (const [month, monthEvents] of eventsByMonth) {
console.log(`${month}: ${monthEvents.length} events`);
monthEvents.forEach(event => {
console.log(` - ${event.displayTitle}`);
});
}
// Get events in a custom date range
import { parseISO } from 'date-fns';
const customStart = parseISO('2024-02-01');
const customEnd = parseISO('2024-02-28');
const customRangeEvents = getEventsInDateRange(events, customStart, customEnd);
console.log(`Events in custom range: ${customRangeEvents.length}`);
// Chain timeframe helpers with other utilities
const activeThisWeek = getEventsThisWeek(events).filter(event => event.isActive);
const sortedNextMonth = getEventsNextMonth(events).sort((a, b) => {
const aDate = a.properties.dateRange.value?.start || new Date(0);
const bDate = b.properties.dateRange.value?.start || new Date(0);
return aDate.getTime() - bDate.getTime();
});Complete Timeframe Helper Example
// Sample Notion API page data for demonstration
const sampleNotionPages = [
{
object: 'page' as const,
id: 'event-1',
url: 'https://notion.so/event-1',
public_url: null,
created_time: '2024-01-15T10:00:00.000Z',
last_edited_time: '2024-01-15T10:00:00.000Z',
created_by: { object: 'user' as const, id: 'user-1' },
last_edited_by: { object: 'user' as const, id: 'user-1' },
cover: null,
icon: null,
parent: { type: 'database_id' as const, database_id: 'database-1' },
archived: false,
in_trash: false,
properties: {
'title': {
id: 'title',
type: 'title',
title: [{
type: 'text',
text: { content: 'Mercury Retrograde in Pisces', link: null },
annotations: {
bold: false,
italic: false,
strikethrough: false,
underline: false,
code: false,
color: 'default',
},
plain_text: 'Mercury Retrograde in Pisces',
href: null,
}]
},
'HC%3Fx': {
id: 'HC%3Fx',
type: 'multi_select',
multi_select: [{ id: 'option-1', name: 'Pisces', color: 'blue' }]
},
'LHB%3E': {
id: 'LHB%3E',
type: 'multi_select',
multi_select: [{ id: 'option-2', name: 'Mercury', color: 'yellow' }]
},
'kly%5E': {
id: 'kly%5E',
type: 'select',
select: { id: 'option-3', name: 'Mercury Course', color: 'green' }
},
'qegM': {
id: 'qegM',
type: 'date',
date: {
start: new Date().toISOString(), // Today
end: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString() // 7 days from now
}
}
}
}
];
// Demonstrate timeframe helper functions
function demonstrateTimeframeHelpers() {
console.log('=== Timeframe Helper Functions Demo ===\n');
// Parse the sample pages into AstroEventPage objects
const events = sampleNotionPages.map(page => parseAstroEventPage(page));
console.log(`Total events: ${events.length}\n`);
// Get events happening today
const todayEvents = getEventsToday(events);
console.log(`Events happening today: ${todayEvents.length}`);
todayEvents.forEach(event => {
console.log(` - ${event.displayTitle} (${event.displayDate})`);
});
console.log();
// Get events happening this week
const thisWeekEvents = getEventsThisWeek(events);
console.log(`Events happening this week: ${thisWeekEvents.length}`);
thisWeekEvents.forEach(event => {
console.log(` - ${event.displayTitle} (${event.displayDate})`);
});
console.log();
// Group events by month
const eventsByMonth = groupEventsByMonth(events);
console.log('Events grouped by month:');
for (const [month, monthEvents] of eventsByMonth) {
console.log(` ${month}: ${monthEvents.length} events`);
monthEvents.forEach(event => {
console.log(` - ${event.displayTitle}`);
});
}
console.log();
}
// Example of chaining timeframe helpers with other utilities
function demonstrateChainedOperations() {
console.log('=== Chained Operations Demo ===\n');
const events = sampleNotionPages.map(page => parseAstroEventPage(page));
// Get this week's events and filter for active ones
const activeThisWeek = getEventsThisWeek(events).filter(event => event.isActive);
console.log(`Active events this week: ${activeThisWeek.length}`);
// Get next month's events and sort by date
const nextMonthEvents = getEventsNextMonth(events);
const sortedNextMonth = nextMonthEvents.sort((a, b) => {
const aDate = a.properties.dateRange.value?.start || new Date(0);
const bDate = b.properties.dateRange.value?.start || new Date(0);
return aDate.getTime() - bDate.getTime();
});
console.log(`Next month's events (sorted):`);
sortedNextMonth.forEach(event => {
console.log(` - ${event.displayTitle} (${event.displayDate})`);
});
// Group events by month and show only those with multiple events
const eventsByMonth = groupEventsByMonth(events);
const busyMonths = Array.from(eventsByMonth.entries())
.filter(([, monthEvents]) => monthEvents.length > 1);
console.log(`\nMonths with multiple events:`);
busyMonths.forEach(([month, monthEvents]) => {
console.log(` ${month}: ${monthEvents.length} events`);
});
}Timeframe Helper Details
| Function | Description | Returns |
| ------------------------------------------ | --------------------------------------------------------- | ------------------------------- |
| getEventsToday(events) | Events that start, end, or are active on the current date | AstroEventPage[] |
| getEventsThisWeek(events) | Events during the current week (Monday to Sunday) | AstroEventPage[] |
| getEventsNextWeek(events) | Events during the next week (Monday to Sunday) | AstroEventPage[] |
| getEventsThisMonth(events) | Events during the current month | AstroEventPage[] |
| getEventsNextMonth(events) | Events during the next month | AstroEventPage[] |
| groupEventsByMonth(events) | Groups events by month (YYYY-MM format) | Map<string, AstroEventPage[]> |
| getEventsInDateRange(events, start, end) | Events within a custom date range | AstroEventPage[] |
Raw Notion API Access
// Access raw Notion API data exactly as provided
const rawPage = exampleNotionResponse.results[0];
// Direct property access
const titleProperty = rawPage.properties['title'];
console.log(titleProperty.title[0].plain_text); // "Sun is in Virgo"
const signProperty = rawPage.properties['HC%3Fx'];
console.log(signProperty.multi_select[0].name); // "Virgo"
const dateProperty = rawPage.properties['qegM'];
console.log(dateProperty.date.start); // "2025-09-16T00:00:00.000Z"Notion API Data Structure
The library works with the exact structure provided by the Notion API:
Page Object
interface NotionPage {
object: 'page';
id: string;
url: string;
public_url?: string | null;
created_time: string;
last_edited_time: string;
created_by?: { object: 'user'; id: string };
last_edited_by?: { object: 'user'; id: string };
cover: null | { type: 'external' | 'file'; external?: { url: string }; file?: { url: string; expiry_time: string } };
icon: null | { type: 'emoji' | 'external' | 'file'; emoji?: string; external?: { url: string }; file?: { url: string; expiry_time: string } };
parent: { type: 'database_id' | 'page_id' | 'workspace'; database_id?: string; page_id?: string; workspace?: boolean };
archived: boolean;
in_trash: boolean;
properties: Record<string, NotionProperty>;
}Property Types
interface NotionProperty {
id: string;
type: string;
[key: string]: any;
}Page Decorator
interface AstroEventPage extends NotionPage {
// All Notion API properties preserved exactly
properties: AstroEventProperties; // Parsed astrological properties
// Computed properties based only on Notion API data
displayTitle: string;
displayDate: string;
isActive: boolean;
// Methods for working with Notion API data
getPropertyValue(propertyName: string): any;
getPropertyDisplayValue(propertyName: string): string;
getAstrologicalSummary(): string;
}Astrological Event Properties
The library parses specific Notion database properties for astrological events:
Supported Property Types
- Title: Page name (e.g., "Mercury Retrograde in Pisces")
- Multi-select: Zodiac signs and planets/events
- Select: Event type notifications
- Date: Event date ranges with timezone support
Property Mapping
// Actual Notion database property IDs
const propertyMapping = {
'title': 'title', // Page name
'Sign the Planet is in': 'HC%3Fx', // Multi-select
'Planet/Event': 'LHB%3E', // Multi-select
'Event Type (Notification)': 'kly%5E', // Select
'Date Range': 'qegM', // Date
};Advanced Usage
Working with Multiple Pages
import { parseAstroEventPage } from '@keithce/astro-notion-db';
// Parse multiple Notion API pages
const pages = notionApiPages.map(page =>
parseAstroEventPage(page)
);
// Filter based on Notion API data
const activeEvents = pages.filter(page => page.isActive);
const mercuryEvents = pages.filter(page =>
page.properties.planetEvent.value.includes('Mercury')
);Property Validation
// Validate that properties exist in Notion API response
function validateNotionPage(page: NotionPage): boolean {
const requiredProperties = ['title', 'HC%3Fx', 'LHB%3E', 'kly%5E', 'qegM'];
return requiredProperties.every(propId =>
page.properties[propId] !== undefined
);
}Error Handling
import { AstroEventParseError } from '@keithce/astro-notion-db';
try {
const page = parseAstroEventPage(notionApiPage);
} catch (error) {
if (error instanceof AstroEventParseError) {
console.error('Failed to parse Notion API page:', error.message);
console.error('Cause:', error.cause);
}
}Type Safety
All functionality is fully typed with strict Notion API adherence:
import type {
AstroEventPage,
NotionPage,
NotionProperty
} from '@keithce/astro-notion-db';
// Type-safe property access
function processNotionPage(page: NotionPage) {
const titleProperty = page.properties['title'];
const titleText = titleProperty.title[0].plain_text; // Type-safe
// Type-safe page usage
const astroPage: AstroEventPage = parseAstroEventPage(page);
const summary = astroPage.getAstrologicalSummary(); // Type-safe
}Migration from Previous Versions
If you're upgrading from a previous version that included inferred data:
// Old way (with inferred data)
const oldPage = parseAstroEventPage(rawNotionPage);
console.log(oldPage.metadata.title); // Inferred data
// New way (strict Notion API)
const page = parseAstroEventPage(notionApiPage);
console.log(page.displayTitle); // Based only on Notion API data
console.log(page.properties.name.value); // Direct API dataExamples
The README now contains comprehensive working examples that demonstrate all the library's functionality. You can copy and paste these examples directly into your code to get started quickly.
Quick Start Example
import { parseAstroEventPage, getEventsToday } from '@keithce/astro-notion-db';
// Parse a single Notion API page
const page = parseAstroEventPage(notionApiPage);
// Get events happening today
const events = [page]; // Your array of parsed pages
const todayEvents = getEventsToday(events);
console.log(`Events today: ${todayEvents.length}`);
todayEvents.forEach(event => {
console.log(`- ${event.displayTitle} (${event.displayDate})`);
});API Reference
AstroEventPage Properties
| Property | Type | Description |
| ------------------ | ---------------------- | --------------------------------------- |
| object | 'page' | Notion API object type |
| id | string | Unique page identifier from Notion API |
| url | string | Notion page URL |
| public_url | string \| null | Public URL if available |
| created_time | string | ISO timestamp from Notion API |
| last_edited_time | string | ISO timestamp from Notion API |
| created_by | User \| undefined | User who created the page |
| last_edited_by | User \| undefined | User who last edited the page |
| cover | Cover \| null | Page cover from Notion API |
| icon | Icon \| null | Page icon from Notion API |
| parent | Parent | Parent object from Notion API |
| archived | boolean | Archive status from Notion API |
| in_trash | boolean | Trash status from Notion API |
| properties | AstroEventProperties | Parsed astrological properties |
| displayTitle | string | Computed title from Notion API data |
| displayDate | string | Formatted date from Notion API data |
| isActive | boolean | Active status based on Notion API dates |
Property Methods
| Method | Parameters | Returns | Description |
| ------------------------- | ---------------------- | -------- | -------------------------------------- |
| getPropertyValue | propertyName: string | any | Get raw property value from Notion API |
| getPropertyDisplayValue | propertyName: string | string | Get formatted property value |
| getAstrologicalSummary | None | string | Generate summary from Notion API data |
Timeframe Helper Functions
| Function | Parameters | Returns | Description |
| ---------------------- | -------------------------------------------------- | ------------------------------- | ------------------------------- |
| getEventsToday | events: AstroEventPage[] | AstroEventPage[] | Get events happening today |
| getEventsThisWeek | events: AstroEventPage[] | AstroEventPage[] | Get events happening this week |
| getEventsNextWeek | events: AstroEventPage[] | AstroEventPage[] | Get events happening next week |
| getEventsThisMonth | events: AstroEventPage[] | AstroEventPage[] | Get events happening this month |
| getEventsNextMonth | events: AstroEventPage[] | AstroEventPage[] | Get events happening next month |
| groupEventsByMonth | events: AstroEventPage[] | Map<string, AstroEventPage[]> | Group events by month |
| getEventsInDateRange | events: AstroEventPage[], start: Date, end: Date | AstroEventPage[] | Get events in custom date range |
Standardized Parsing with Error Handling
The library now provides a robust, standardized parsing function that accepts official Notion client database responses and returns a consistent JSON response format with comprehensive error handling.
New Standardized Parser
import { parseAstroEventPages } from '@keithce/astro-notion-db';
import type { NotionClientDatabaseResponse, ParseResponse, AstroEventPage } from '@keithce/astro-notion-db';
// Parse a Notion client database response
const result: ParseResponse<AstroEventPage[]> = parseAstroEventPages(notionClientResponse);
// Check the result
if (result.status === 'success') {
console.log(`Successfully parsed ${result.data?.length} pages`);
console.log(result.message);
// Use the parsed data
result.data?.forEach(page => {
console.log(page.displayTitle);
});
} else {
console.error('Parsing failed:', result.message);
console.log('Data:', result.data); // null on error
}Response Format
The parseAstroEventPages() function returns a standardized response object:
interface ParseResponse<T> {
data: T | null; // Parsed data if successful, null if error
status: 'success' | 'error'; // Indicates parsing success or failure
message: string; // Detailed status or error message
}Input Validation
The function performs comprehensive validation:
- Response Structure: Validates the Notion client response format
- Page Structure: Validates each page object structure
- Required Properties: Ensures all required astrological event properties are present
- Property Types: Validates property types and structures
Error Handling
The function handles various error scenarios:
- Invalid Response Structure: Returns error for malformed Notion responses
- Missing Properties: Detailed error messages for missing required properties
- Partial Failures: Continues parsing other pages if some fail
- Type Errors: Comprehensive type checking with helpful error messages
- Runtime Errors: Catches and reports unexpected errors
Example Error Scenarios
// Invalid response structure
const invalidResult = parseAstroEventPages({ object: 'invalid' } as any);
// Returns: { status: 'error', data: null, message: 'Invalid Notion client response structure' }
// Missing required properties
const incompleteResult = parseAstroEventPages(incompleteResponse);
// Returns: { status: 'error', data: null, message: 'Failed to parse any pages. Errors: Index 0: Missing required property: HC%3Fx' }
// Mixed success/failure
const mixedResult = parseAstroEventPages(mixedResponse);
// Returns: { status: 'success', data: [parsedPages], message: 'Successfully parsed 2 pages. 1 pages failed to parse: Index 1: Missing required property: LHB%3E' }Backward Compatibility
The legacy function is still available for backward compatibility:
import { parseAstroEventPagesLegacy } from '@keithce/astro-notion-db';
const pages = parseAstroEventPagesLegacy(rawPagesArray);Type Safety
The function is fully typed with official Notion SDK compatibility:
import type { NotionClientDatabaseResponse } from '@keithce/astro-notion-db';
// Compatible with @notionhq/client SDK response
const response: NotionClientDatabaseResponse = await notion.databases.query({
database_id: 'your-database-id'
});
const result = parseAstroEventPages(response);Core Functionality
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Ensure all changes strictly adhere to Notion API specifications
- Add tests for new functionality
- Submit a pull request
License
MIT License - see LICENSE file for details.
