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

@timesheet/plugin-notion

v1.3.1

Published

Synchronize Timesheet todos and time entries with Notion databases

Readme

Notion Sync

Synchronize Timesheet todos and time entries with Notion databases.

Bidirectional synchronization between Timesheet and Notion. Timesheet todos are mirrored 1:1 with pages in the mapped Notion database; Timesheet time entries (tasks) optionally sync as rows of a time-log database, related to the todo's page. Changes made in Notion flow back through webhooks and scheduled syncs.

  • Package: @timesheet/plugin-notion
  • Manifest id: notion-sync
  • Category: project-management

Authentication

OAuth 2.0 against Notion (api.notion.com/v1/oauth). Three Notion-specific deviations:

  • The token endpoint expects HTTP Basic auth (client_id:client_secret), like Intuit.
  • There are no OAuth scopes; capabilities are configured on the integration in Notion's developer dashboard, and the user selects which pages/databases to share during the OAuth flow. Only shared databases are visible to the plugin.
  • Access tokens do not expire and there is no refresh token; the client tolerates a failing refreshToken and surfaces the original 401 (which means the share was revoked).

All requests are pinned to Notion-Version: 2022-06-28. Notion rate-limits at roughly 3 requests/second; the client retries 429s honoring Retry-After.

Configuration

| Option | Required | Default | Description | | --- | --- | --- | --- | | syncDirection | yes | bidirectional | One of bidirectional, timesheet-to-notion, notion-to-timesheet. | | timeLogDatabaseId | no | (unset) | Notion database id for time entries. When set, Timesheet tasks sync as rows of this database. | | statusProperty | no | auto | Property name for todo status; auto-detected otherwise. | | dueDateProperty | no | auto | Date property name for todo due dates; auto-detected otherwise. |

Mappings

  • Project mapping (required): Timesheet project to Notion database. Each page (row) of the database is a Timesheet todo.
  • User mapping: Timesheet user to Notion user. Optional, and only needed for teams. Bots are excluded from the candidates, including this integration's own bot.

Property discovery

Notion databases are schemaless, so the plugin discovers the relevant properties from each database's schema and caches them in plugin state (the monday board-columns pattern):

  • Title: the title property (always exists) carries the todo name / time-entry description.
  • Status: first status property (else first checkbox). For status properties the done/open options come from the schema's Complete and To-do groups.
  • Due date: first date property.
  • Time-log databases additionally resolve the first number property (hours) and first relation property (link to the todo's page).

Config overrides (statusProperty, dueDateProperty) win when they name an existing property.

Time entries (time-log database)

With timeLogDatabaseId set, each Timesheet task becomes a row: title = description, date property = start/end datetime range, number property = net worked hours (duration - durationBreak), relation = the todo's page. Inbound edits to time-log rows flow back to the local task; rows without a relation to a synced todo page are skipped (no local project context).

Triggers

  • Timesheet Changed (event): pushes todo and task create/update/delete events to Notion.
  • Notion Webhook (webhook): receives inbound page changes.
  • Scheduled Full Sync (daily at 02:00 UTC): reconciles both directions.
  • Manual Sync (user action): pulls pages edited since the last run.

Webhook

Notion webhook subscriptions are app-level: one URL per integration, configured in Notion's developer dashboard (not per-user via API). Deliveries carry workspace_id, so the backend routes each event to the installation whose credential holds that workspace (captured from the OAuth token response), the same model as the QuickBooks app-level webhook. The one-time handshake delivery carries a verification_token, which the handler stores as the HMAC secret; subsequent deliveries are verified against X-Notion-Signature (sha256=<hex> over the raw body).

Deletes and archiving

Notion has no hard delete via API: outbound deletes archive the page (move to trash). Inbound deletes only arrive via the page.deleted webhook event or as an archived page on fetch, because database queries exclude archived pages; the scheduled full sync therefore does not detect deletions on its own.

Echo suppression caveat

Notion truncates last_edited_time to the minute. The standard SDK guards apply (isAlreadySyncedLocalChange outbound, isStaleExternalChange on lastEditedTime inbound), but a genuine Notion edit within the same minute as the plugin's own write compares stale and is picked up by the next edit or scheduled full sync.

Organization installs

Inbound work runs as the installing admin, so without a user mapping every member's imported time is booked on that admin. With the mapping in place, an imported time log is booked on the member behind the page's created_by. Once any user is mapped, records belonging to someone this installation has not mapped are skipped rather than booked on the admin: attribution is create-only, because TaskUpdateInput carries no userId, so a wrong owner can never be corrected afterwards.

Outbound attribution is not wired up: pages Timesheet writes are created by the integration's own bot user, which is what Notion records as created_by for anything an integration token creates. A people property on the time-log database could carry the member instead, but that would need a new property mapping.

Development

npm install        # or: npm ci
npm run build      # compile TypeScript into dist/
npm run typecheck

The package ships dist/ and manifest.json; the sandboxed plugin runtime loads it by package name, version, and integrity (sha512-...). Shared tests live in integrations/tests/ and run from the integrations/ root with npm test.