npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@keithce/astro-notion-db

v2.9.0

Published

TypeScript library for working with astrological events in Notion database

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-db

Basic 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 data

Examples

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:

  1. Response Structure: Validates the Notion client response format
  2. Page Structure: Validates each page object structure
  3. Required Properties: Ensures all required astrological event properties are present
  4. 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

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Ensure all changes strictly adhere to Notion API specifications
  5. Add tests for new functionality
  6. Submit a pull request

License

MIT License - see LICENSE file for details.