From 7efde269eaf1a1cb86918b63a663a1504f5c914f Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Wed, 27 Aug 2025 17:57:55 -0400 Subject: [PATCH 1/4] new sources --- components/notion/package.json | 2 +- .../notion/sources/common/base-webhook.mjs | 56 ++++++++++++ .../new-webhook-event-instant.mjs | 27 ++++++ .../new-webhook-event-instant/test-event.mjs | 31 +++++++ .../page-properties-updated-instant.mjs | 89 +++++++++++++++++++ .../test-event.mjs | 37 ++++++++ 6 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 components/notion/sources/common/base-webhook.mjs create mode 100644 components/notion/sources/new-webhook-event-instant/new-webhook-event-instant.mjs create mode 100644 components/notion/sources/new-webhook-event-instant/test-event.mjs create mode 100644 components/notion/sources/page-properties-updated-instant/page-properties-updated-instant.mjs create mode 100644 components/notion/sources/page-properties-updated-instant/test-event.mjs diff --git a/components/notion/package.json b/components/notion/package.json index b1d1185b430ce..e2487a63a8fa1 100644 --- a/components/notion/package.json +++ b/components/notion/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/notion", - "version": "0.9.1", + "version": "0.10.0", "description": "Pipedream Notion Components", "main": "notion.app.mjs", "keywords": [ diff --git a/components/notion/sources/common/base-webhook.mjs b/components/notion/sources/common/base-webhook.mjs new file mode 100644 index 0000000000000..1a60da7f1083b --- /dev/null +++ b/components/notion/sources/common/base-webhook.mjs @@ -0,0 +1,56 @@ +import notion from "../../notion.app.mjs"; +import { + createHmac, timingSafeEqual, +} from "crypto"; +import { ConfigurationError } from "@pipedream/platform"; + +export default { + props: { + notion, + db: "$.service.db", + http: "$.interface.http", + info: { + type: "alert", + alertType: "info", + content: "Webhooks must be created and verified in Notion. [See the documentation](https://developers.notion.com/reference/webhooks#step-1-creating-a-webhook-subscription). Upon webhook creation, the source logs will display a verification token. Enter this in your Notion webhook settings.", + }, + }, + methods: { + _getToken() { + return this.db.get("token"); + }, + _setToken(token) { + this.db.set("token", token); + }, + verifyWebhook(token, body, headers) { + const calculatedSignature = `sha256=${createHmac("sha256", token).update(JSON.stringify(body)) + .digest("hex")}`; + return timingSafeEqual( + Buffer.from(calculatedSignature), + Buffer.from(headers["x-notion-signature"]), + ); + }, + processEvent() { + throw new ConfigurationError("processEvent must be implemented in the source"); + }, + }, + async run(event) { + const { + body, headers, + } = event; + if (!body) { + return; + } + const token = this._getToken(); + if (body.verification_token && !token) { + this._setToken(body.verification_token); + console.log(`Verification token: ${body.verification_token}. Enter this in your Notion webhook settings.`); + return; + } + if (!this.verifyWebhook(token, body, headers)) { + throw new Error("Invalid webhook signature"); + } + + await this.processEvent(body); + }, +}; diff --git a/components/notion/sources/new-webhook-event-instant/new-webhook-event-instant.mjs b/components/notion/sources/new-webhook-event-instant/new-webhook-event-instant.mjs new file mode 100644 index 0000000000000..c4bf8ec8225cb --- /dev/null +++ b/components/notion/sources/new-webhook-event-instant/new-webhook-event-instant.mjs @@ -0,0 +1,27 @@ +import common from "../common/base-webhook.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "notion-new-webhook-event-instant", + name: "New Webhook Event (Instant)", + description: "Emit new event each time a webhook event is received. Webhook must be setup in Notion. [See the documentation](https://developers.notion.com/reference/webhooks#step-1-creating-a-webhook-subscription)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + _generateMeta(event) { + return { + id: event.id, + summary: `Webhook event: ${event.type}`, + ts: Date.now(), + }; + }, + processEvent(event) { + const meta = this._generateMeta(event); + this.$emit(event, meta); + }, + }, + sampleEmit, +}; diff --git a/components/notion/sources/new-webhook-event-instant/test-event.mjs b/components/notion/sources/new-webhook-event-instant/test-event.mjs new file mode 100644 index 0000000000000..73c6a1188a313 --- /dev/null +++ b/components/notion/sources/new-webhook-event-instant/test-event.mjs @@ -0,0 +1,31 @@ +export default { + "id": "555831bd-c1d6-400b-873e-42b10fb7f7e8", + "timestamp": "2025-08-27T20:51:19.356Z", + "workspace_id": "e0f732bd-e43f-4db3-b923-8a12ffdbfcce", + "workspace_name": "Notion", + "subscription_id": "25cd872b-594c-8181-982c-009998a96535", + "integration_id": "1ded872b-594c-804e-88d9-0037511f15c1", + "authors": [ + { + "id": "22da95d5-0f61-4b51-963d-63c4cf51ae19", + "type": "person" + } + ], + "attempt_number": 1, + "api_version": "2022-06-28", + "entity": { + "id": "10773a03-a25e-8061-8256-f26813633a59", + "type": "page" + }, + "type": "page.properties_updated", + "data": { + "parent": { + "id": "9813bf8c-a429-4d63-b73b-f476783ff448", + "type": "database", + "data_source_id": "dabbe504-b5ff-48f1-a1fa-d5fea5ef9ac4" + }, + "updated_properties": [ + "title" + ] + } +} \ No newline at end of file diff --git a/components/notion/sources/page-properties-updated-instant/page-properties-updated-instant.mjs b/components/notion/sources/page-properties-updated-instant/page-properties-updated-instant.mjs new file mode 100644 index 0000000000000..01dc1ae08ae99 --- /dev/null +++ b/components/notion/sources/page-properties-updated-instant/page-properties-updated-instant.mjs @@ -0,0 +1,89 @@ +import common from "../common/base-webhook.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "notion-page-properties-updated-instant", + name: "Page Properties Updated (Instant)", + description: "Emit new event each time a page property is updated in a database. For use with Page Properties Updated event type. Webhook must be setup in Notion. [See the documentation](https://developers.notion.com/reference/webhooks#step-1-creating-a-webhook-subscription)", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + ...common.props, + databaseId: { + propDefinition: [ + common.props.notion, + "databaseId", + ], + }, + properties: { + type: "string[]", + label: "Properties", + description: "Only emit events when one or more of the selected properties have changed", + optional: true, + async options() { + try { + const { properties } = await this.notion.retrieveDatabase(this.databaseId); + const propEntries = Object.entries(properties); + return propEntries.map((prop) => ({ + label: prop[1].name, + value: prop[1].id, + })); + } catch (error) { + console.log(error); + return []; + } + }, + }, + }, + methods: { + ...common.methods, + _generateMeta(page) { + const { id } = page; + const title = this.notion.extractPageTitle(page); + const ts = Date.now(); + return { + id: `${id}-${ts}`, + summary: `Page updated: ${title}`, + ts, + }; + }, + async processEvent(event) { + if (event?.type !== "page.properties_updated") { + console.log(`Skipping event type: ${event?.type}`); + return; + } + + if (event.data.parent.id !== this.databaseId) { + console.log(`Skipping event for database: ${event.data.parent.id}`); + return; + } + + const updatedProperties = event.data.updated_properties; + if (!updatedProperties?.length) { + return; + } + + let propertyHasChanged = false; + for (const propertyName of updatedProperties) { + if (!this.properties || this.properties.includes(propertyName)) { + propertyHasChanged = true; + } + } + + if (!propertyHasChanged) { + return; + } + + const page = await this.notion.retrievePage(event.entity.id); + + const meta = this._generateMeta(page); + this.$emit({ + ...event, + page, + }, meta); + }, + }, + sampleEmit, +}; diff --git a/components/notion/sources/page-properties-updated-instant/test-event.mjs b/components/notion/sources/page-properties-updated-instant/test-event.mjs new file mode 100644 index 0000000000000..8fc730221c4a4 --- /dev/null +++ b/components/notion/sources/page-properties-updated-instant/test-event.mjs @@ -0,0 +1,37 @@ +export default { + "id": "1782edd6-a853-4d4a-b02c-9c8c16f28e53", + "timestamp": "2024-12-05T23:57:05.379Z", + "workspace_id": "13950b26-c203-4f3b-b97d-93ec06319565", + "workspace_name": "Quantify Labs", + "subscription_id": "29d75c0d-5546-4414-8459-7b7a92f1fc4b", + "integration_id": "0ef2e755-4912-8096-91c1-00376a88a5ca", + "type": "page.properties_updated", + "authors": [ + { + "id": "c7c11cca-1d73-471d-9b6e-bdef51470190", + "type": "person" + } + ], + "accessible_by": [ + { + "id": "556a1abf-4f08-40c6-878a-75890d2a88ba", + "type": "person" + }, + { + "id": "1edc05f6-2702-81b5-8408-00279347f034", + "type": "bot" + } + ], + "attempt_number": 1, + "entity": { + "id": "153104cd-477e-809d-8dc4-ff2d96ae3090", + "type": "page" + }, + "data": { + "parent": { + "id": "13950b26-c203-4f3b-b97d-93ec06319565", + "type": "space" + }, + "updated_properties": ["XGe%40", "bDf%5B", "DbAu"] + } +} \ No newline at end of file From 487328ab7bcc597ca50b68c057330b4f9770fd00 Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Wed, 27 Aug 2025 17:58:28 -0400 Subject: [PATCH 2/4] pnpm-lock.yaml --- pnpm-lock.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d0ae2a4b1af18..6cef1bd3a0115 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1626,8 +1626,7 @@ importers: components/bill: {} - components/billbee: - specifiers: {} + components/billbee: {} components/billplz: {} @@ -38897,6 +38896,8 @@ snapshots: '@putout/operator-filesystem': 5.0.0(putout@36.13.1(eslint@8.57.1)(typescript@5.6.3)) '@putout/operator-json': 2.2.0 putout: 36.13.1(eslint@8.57.1)(typescript@5.6.3) + transitivePeerDependencies: + - supports-color '@putout/operator-regexp@1.0.0(putout@36.13.1(eslint@8.57.1)(typescript@5.6.3))': dependencies: From 979a81322bdbf664d1502ae6e8e1d736875d804f Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Wed, 27 Aug 2025 18:12:47 -0400 Subject: [PATCH 3/4] update --- .../page-properties-updated-instant.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/notion/sources/page-properties-updated-instant/page-properties-updated-instant.mjs b/components/notion/sources/page-properties-updated-instant/page-properties-updated-instant.mjs index 01dc1ae08ae99..c0dfecb251f9e 100644 --- a/components/notion/sources/page-properties-updated-instant/page-properties-updated-instant.mjs +++ b/components/notion/sources/page-properties-updated-instant/page-properties-updated-instant.mjs @@ -5,7 +5,7 @@ export default { ...common, key: "notion-page-properties-updated-instant", name: "Page Properties Updated (Instant)", - description: "Emit new event each time a page property is updated in a database. For use with Page Properties Updated event type. Webhook must be setup in Notion. [See the documentation](https://developers.notion.com/reference/webhooks#step-1-creating-a-webhook-subscription)", + description: "Emit new event each time a page property is updated in a database. For use with Page Properties Updated event type. Webhook must be set up in Notion. [See the documentation](https://developers.notion.com/reference/webhooks#step-1-creating-a-webhook-subscription)", version: "0.0.1", type: "source", dedupe: "unique", From b309fc1987933cec22e25365e0a8a2d679051644 Mon Sep 17 00:00:00 2001 From: Leo Vu Date: Thu, 28 Aug 2025 09:11:09 +0700 Subject: [PATCH 4/4] Update webhook setup instructions for clarity and detail --- components/notion/sources/common/base-webhook.mjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/notion/sources/common/base-webhook.mjs b/components/notion/sources/common/base-webhook.mjs index 1a60da7f1083b..5bd3cd1704fb5 100644 --- a/components/notion/sources/common/base-webhook.mjs +++ b/components/notion/sources/common/base-webhook.mjs @@ -12,7 +12,9 @@ export default { info: { type: "alert", alertType: "info", - content: "Webhooks must be created and verified in Notion. [See the documentation](https://developers.notion.com/reference/webhooks#step-1-creating-a-webhook-subscription). Upon webhook creation, the source logs will display a verification token. Enter this in your Notion webhook settings.", + content: `1. Create this Pipedream source and copy the Source Endpoint URL. +2. In Notion, create a webhook subscription and paste the Source Endpoint URL as the webhook URL. See Notion's guide: https://developers.notion.com/reference/webhooks#step-1-creating-a-webhook-subscription +3. After adding the subscription in Notion, you'll be prompted to verify the webhook using a secret. Open the Source Logs tab in this Pipedream source to find the verification secret (token) and enter it in Notion to complete verification.`, }, }, methods: {