Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/notion/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pipedream/notion",
"version": "0.9.1",
"version": "0.10.0",
"description": "Pipedream Notion Components",
"main": "notion.app.mjs",
"keywords": [
Expand Down
58 changes: 58 additions & 0 deletions components/notion/sources/common/base-webhook.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
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: {

Check warning on line 12 in components/notion/sources/common/base-webhook.mjs

View workflow job for this annotation

GitHub Actions / Lint Code Base

Component prop info must have a description. See https://pipedream.com/docs/components/guidelines/#props

Check warning on line 12 in components/notion/sources/common/base-webhook.mjs

View workflow job for this annotation

GitHub Actions / Lint Code Base

Component prop info must have a label. See https://pipedream.com/docs/components/guidelines/#props
type: "alert",
alertType: "info",
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: {
_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);
},
};
Original file line number Diff line number Diff line change
@@ -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,
};
31 changes: 31 additions & 0 deletions components/notion/sources/new-webhook-event-instant/test-event.mjs
Original file line number Diff line number Diff line change
@@ -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"
]
}
}
Original file line number Diff line number Diff line change
@@ -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)",

Check warning on line 7 in components/notion/sources/page-properties-updated-instant/page-properties-updated-instant.mjs

View workflow job for this annotation

GitHub Actions / Lint Code Base

Source names should start with "New". See https://pipedream.com/docs/components/guidelines/#source-name
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",
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,
};
Original file line number Diff line number Diff line change
@@ -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"]
}
}
5 changes: 3 additions & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading