@keystrokehq/notion 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # `@keystrokehq/notion`
2
+
3
+ Official Notion integration for Keystroke.
4
+
5
+ ## Import Paths
6
+
7
+ Use explicit subpath imports. The package root is intentionally non-canonical.
8
+
9
+ ```ts
10
+ import { notion } from '@keystrokehq/notion/connection';
11
+ import { copyPageContent, createPage, getPage } from '@keystrokehq/notion/pages';
12
+ import { listBlockChildren } from '@keystrokehq/notion/blocks';
13
+ import { queryDataSource } from '@keystrokehq/notion/data-sources';
14
+ import { listComments, createComment } from '@keystrokehq/notion/comments';
15
+ import { getMe, listUsers } from '@keystrokehq/notion/users';
16
+ import { searchWorkspace } from '@keystrokehq/notion/search';
17
+ import { webhooks, polling } from '@keystrokehq/notion/triggers';
18
+ ```
19
+
20
+ ## Connection Model
21
+
22
+ The public connection surface normalizes two auth paths into the same runtime credential shape:
23
+
24
+ - OAuth connection through Keystroke-managed Notion public integrations
25
+ - Manual internal-integration token entry
26
+
27
+ Both resolve to:
28
+
29
+ ```ts
30
+ {
31
+ NOTION_ACCESS_TOKEN: string;
32
+ }
33
+ ```
34
+
35
+ In practice:
36
+
37
+ - OAuth is the default path when users run `keystroke connect notion`
38
+ - Manual token entry is for internal Notion integrations that already have a bearer token
39
+
40
+ ## Core Surfaces
41
+
42
+ - `pages`: page reads, property reads, create, content copy, updates, trash, restore
43
+ - `blocks`: block reads, child listing, append, update, delete
44
+ - `data-sources`: canonical data-source discovery and query flows
45
+ - `comments`: page comments and discussion replies
46
+ - `users`: `me`, single-user lookup, workspace user listing
47
+ - `search`: workspace-wide page and data-source discovery
48
+ - `triggers`: webhook-first direct bindings plus polling parity helpers
49
+
50
+ `data_source` is the canonical runtime model in this package. Database discovery is still available for the upgrade path, but author-facing operations prefer `data_source` IDs over legacy database query endpoints.
51
+
52
+ For duplication-style workflows, pair `createPage` with `copyPageContent`. The helper recreates supported block trees level by level so it stays inside Notion's append limits. Pages containing API-unsupported block types such as `child_page`, `child_database`, or `link_preview` should use a template-driven flow instead.
53
+
54
+ ## Trigger Examples
55
+
56
+ ```ts
57
+ import { webhooks, polling } from '@keystrokehq/notion/triggers';
58
+
59
+ const pageCreated = webhooks.pageCreated({
60
+ name: 'Notion Page Created',
61
+ transform: (event) => ({
62
+ pageId: event.entityId,
63
+ eventType: event.eventType,
64
+ }),
65
+ });
66
+
67
+ const pageUpdated = polling.pageUpdated({
68
+ name: 'Notion Page Updated',
69
+ pageId: 'notion-page-id',
70
+ schedule: '*/10 * * * *',
71
+ });
72
+ ```
73
+
74
+ Webhook bindings emit metadata-first payloads. They intentionally do not auto-hydrate full Notion objects. Use the page, comment, or data-source operations to fetch current state when the workflow needs it.
75
+
76
+ ## Platform Admin Setup
77
+
78
+ Notion webhook subscriptions are configured in Notion, not through the public API. A Keystroke platform admin must complete the bootstrap:
79
+
80
+ 1. Create or update the Keystroke-managed Notion public integration in Notion.
81
+ 2. Enable the minimum capabilities the shipped surface expects:
82
+ - Read content
83
+ - Insert content
84
+ - Update content
85
+ - Read comment
86
+ - Insert comment
87
+ - User information
88
+ 3. Configure the OAuth redirect URL to Keystroke's `/api/v1/connections/callback`.
89
+ 4. Configure the webhook destination URL to Keystroke's `/api/v1/webhooks/{orgId}/notion`.
90
+ 5. Store the Notion OAuth app credentials in the internal `notion-app` credential set.
91
+ 6. Store the Notion webhook verification token in the internal `notion-webhook` credential set.
92
+
93
+ ## Provider Caveats
94
+
95
+ - Notion OAuth is provider-specific. The Keystroke server uses a Notion-specific auth URL builder and token exchange flow instead of the generic OAuth strategy.
96
+ - Notion webhook payloads are sparse. Event IDs, entity IDs, authors, and event metadata are the contract; workflows should fetch fresh objects when they need content.
97
+ - Notion write operations are approval-gated by default.
98
+
99
+ ## Testing
100
+
101
+ - **Coverage map:** See [`TEST_MATRIX.md`](./TEST_MATRIX.md) for the full list of operations, webhook/polling triggers, and credential/server boundaries and what each must prove (success, failure, safety, live).
102
+ - **Unit / contract:** `pnpm test:unit` — exercises `.run()` paths with mocked `@notionhq/client`, triggers, client helpers, events, verification, and schemas.
103
+ - **Live Notion (`test:int`):** `pnpm test:int` — package-level integration suites in `*.int.test.ts`. Credentials follow a two-tier waterfall via the shared `resolveLiveCredentialsForCredentialSet` helper from `@keystrokehq/test-utils`:
104
+ 1. **Env vars (CI-friendly):** `NOTION_TEST_ACCESS_TOKEN` or `NOTION_TEST_INTEGRATION_TOKEN` in `.env.test`.
105
+ 2. **Saved Keystroke connection (recommended for local dev):** run `pnpm cli auth` + `pnpm cli connect notion` once. The suites then resolve credentials from the Keystroke server (`POST /api/v1/credentials/resolve`), so any OAuth refresh happens server-side and tests never touch the refresh token.
106
+
107
+ **Sandbox parent page is auto-discovered.** The integration test harness calls Notion's search API in `beforeAll` to pick the first page the integration has access to as the sandbox parent. Just share at least one page with your Notion integration (during the OAuth consent, or later via the page share menu) and the page/block/comment/trigger suites will run end-to-end. Set `NOTION_TEST_PARENT_PAGE_ID` to pin a specific page (recommended in CI for deterministic runs).
108
+
109
+ Other fixture IDs (`NOTION_TEST_DATA_SOURCE_ID`, `NOTION_TEST_PAGE_ID`, `NOTION_TEST_PAGE_PROPERTY_ID`, etc.) remain opt-in env overrides; tests that need them `it.skipIf` out cleanly when they are absent. Full list in the root [`.env.test.example`](../../../.env.test.example). Without credentials, the suites skip the whole suite with a warning — no flag flipping required.
110
+ - **Server OAuth:** Database-backed routes are covered under `@keystroke/server` (`connections/.../initiate`, `connections/callback`). Run `turbo run test:int --filter=@keystroke/server` with a local Postgres (see root `.env.test.example`).
@@ -0,0 +1,3 @@
1
+ import { r as notionBundle } from "../integration-C7pL009K.mjs";
2
+ import { a as notionWebhookCredentialSet, i as notionPlatformProviderSeed, n as NotionWebhookCredentials, r as notionAppCredentialSet, t as NotionAppCredentials } from "../provider-app-DehoD5sd.mjs";
3
+ export { NotionAppCredentials, NotionWebhookCredentials, notionAppCredentialSet, notionBundle, notionPlatformProviderSeed, notionWebhookCredentialSet };
@@ -0,0 +1,3 @@
1
+ import { a as notionPlatformProviderSeed, i as notionAppCredentialSet, n as notionBundle, o as notionWebhookCredentialSet } from "../integration-Hfdp-q_v.mjs";
2
+
3
+ export { notionAppCredentialSet, notionBundle, notionPlatformProviderSeed, notionWebhookCredentialSet };