@notionhq/client 5.26.0 → 5.27.0

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.
Files changed (50) hide show
  1. package/README.md +130 -129
  2. package/build/package.json +4 -3
  3. package/build/src/Client.d.ts +1869 -130
  4. package/build/src/Client.d.ts.map +1 -1
  5. package/build/src/Client.js +86 -571
  6. package/build/src/Client.js.map +1 -1
  7. package/build/src/api-endpoint-methods.d.ts +920 -0
  8. package/build/src/api-endpoint-methods.d.ts.map +1 -0
  9. package/build/src/api-endpoint-methods.js +171 -0
  10. package/build/src/api-endpoint-methods.js.map +1 -0
  11. package/build/src/api-endpoints/agent-skills.d.ts +68 -0
  12. package/build/src/api-endpoints/agent-skills.d.ts.map +1 -0
  13. package/build/src/api-endpoints/agent-skills.js +36 -0
  14. package/build/src/api-endpoints/agent-skills.js.map +1 -0
  15. package/build/src/api-endpoints/agents.d.ts +173 -146
  16. package/build/src/api-endpoints/agents.d.ts.map +1 -1
  17. package/build/src/api-endpoints/agents.js.map +1 -1
  18. package/build/src/api-endpoints/data-sources.d.ts +1 -0
  19. package/build/src/api-endpoints/data-sources.d.ts.map +1 -1
  20. package/build/src/api-endpoints/data-sources.js.map +1 -1
  21. package/build/src/api-endpoints/databases.d.ts +3 -1
  22. package/build/src/api-endpoints/databases.d.ts.map +1 -1
  23. package/build/src/api-endpoints/databases.js +1 -0
  24. package/build/src/api-endpoints/databases.js.map +1 -1
  25. package/build/src/api-endpoints/file-uploads.d.ts.map +1 -1
  26. package/build/src/api-endpoints/file-uploads.js.map +1 -1
  27. package/build/src/api-endpoints/pages.d.ts.map +1 -1
  28. package/build/src/api-endpoints/pages.js.map +1 -1
  29. package/build/src/api-endpoints/users.d.ts.map +1 -1
  30. package/build/src/api-endpoints/users.js.map +1 -1
  31. package/build/src/api-endpoints.d.ts +1 -0
  32. package/build/src/api-endpoints.d.ts.map +1 -1
  33. package/build/src/api-endpoints.js +1 -0
  34. package/build/src/api-endpoints.js.map +1 -1
  35. package/build/src/errors.d.ts +11 -0
  36. package/build/src/errors.d.ts.map +1 -1
  37. package/build/src/errors.js +20 -1
  38. package/build/src/errors.js.map +1 -1
  39. package/build/src/helpers.d.ts +4 -4
  40. package/build/src/helpers.d.ts.map +1 -1
  41. package/build/src/helpers.js.map +1 -1
  42. package/build/src/index.d.ts +2 -2
  43. package/build/src/index.d.ts.map +1 -1
  44. package/build/src/index.js +2 -1
  45. package/build/src/index.js.map +1 -1
  46. package/build/src/webhooks.d.ts +12 -19
  47. package/build/src/webhooks.d.ts.map +1 -1
  48. package/build/src/webhooks.js +27 -35
  49. package/build/src/webhooks.js.map +1 -1
  50. package/package.json +4 -3
@@ -2,19 +2,13 @@
2
2
  /**
3
3
  * Helpers for receiving and verifying Notion webhook deliveries.
4
4
  *
5
- * Notion signs each webhook request with HMAC-SHA256 over the raw HTTP
6
- * body using the subscription's verification token as the key, and sends
7
- * the resulting hex digest in the `X-Notion-Signature` header as
8
- * `sha256=<hex>`. To verify a delivery, callers must pass the body
9
- * **exactly as it arrived over the wire** — any JSON re-serialization
10
- * will change the bytes and invalidate the signature.
5
+ * Event signatures use HMAC-SHA256 with the subscription's verification
6
+ * token. The `X-Notion-Signature` header contains `sha256=<hex>`.
7
+ * Pass the raw body as received. Parsing and re-serializing JSON can change
8
+ * its bytes and invalidate the signature.
11
9
  *
12
- * The helpers prefer the Web Crypto API (`globalThis.crypto.subtle`)
13
- * when present (browsers, edge runtimes, Node.js >= 18.19) and
14
- * transparently fall back to `node:crypto`'s `webcrypto.subtle` on older
15
- * Node.js 18 builds where `globalThis.crypto` is not yet enabled by
16
- * default. They work without configuration in Node.js, Bun, Deno,
17
- * Vercel Edge Functions, Cloudflare Workers, and modern browsers.
10
+ * The helpers use `globalThis.crypto.subtle` when available, then fall
11
+ * back to the Web Crypto API in Node's crypto module.
18
12
  */
19
13
  Object.defineProperty(exports, "__esModule", { value: true });
20
14
  exports.verifyWebhookSignature = verifyWebhookSignature;
@@ -25,29 +19,32 @@ const SHA256_HEX_LENGTH = 64;
25
19
  * Verify that a webhook delivery came from Notion and has not been
26
20
  * tampered with.
27
21
  *
28
- * Performs a constant-time comparison; returns `true` only if the
29
- * supplied `signature` matches HMAC-SHA256 of `body` keyed by
30
- * `verificationToken`. Returns `false` (rather than throwing) for any
31
- * malformed input so the caller can respond with a single 401/403 path.
22
+ * Returns `true` if the signature matches HMAC-SHA256 of the body using
23
+ * the verification token. Returns `false` for a missing or malformed
24
+ * signature. Crypto errors may throw.
32
25
  */
33
26
  async function verifyWebhookSignature(args) {
34
27
  const { body, signature, verificationToken } = args;
35
- if (typeof signature !== "string")
28
+ if (typeof signature !== "string") {
36
29
  return false;
37
- if (!signature.startsWith(SIGNATURE_PREFIX))
30
+ }
31
+ if (!signature.startsWith(SIGNATURE_PREFIX)) {
38
32
  return false;
33
+ }
39
34
  const providedHex = signature.slice(SIGNATURE_PREFIX.length).toLowerCase();
40
- if (providedHex.length !== SHA256_HEX_LENGTH)
35
+ if (providedHex.length !== SHA256_HEX_LENGTH) {
41
36
  return false;
42
- if (!/^[0-9a-f]+$/.test(providedHex))
37
+ }
38
+ if (!/^[0-9a-f]+$/.test(providedHex)) {
43
39
  return false;
40
+ }
44
41
  const computedHex = await computeHmacSha256Hex(verificationToken, body);
45
42
  return timingSafeEqualHex(providedHex, computedHex);
46
43
  }
47
44
  /**
48
45
  * Compute the value Notion would send in `X-Notion-Signature` for a
49
- * given body and verification token. Useful for unit-testing webhook
50
- * handlers without standing up a real subscription.
46
+ * given body and verification token. Use this to test webhook handlers
47
+ * without a live subscription.
51
48
  */
52
49
  async function signWebhookPayload(args) {
53
50
  const hex = await computeHmacSha256Hex(args.verificationToken, args.body);
@@ -68,23 +65,17 @@ async function computeHmacSha256Hex(key, body) {
68
65
  let cachedSubtle;
69
66
  async function getSubtle() {
70
67
  var _a, _b;
71
- if (cachedSubtle)
68
+ if (cachedSubtle) {
72
69
  return cachedSubtle;
73
- // Preferred path: every modern runtime exposes Web Crypto on the
74
- // global object. This includes browsers, Vercel Edge, Cloudflare
75
- // Workers, Deno, Bun, and Node.js >= 18.19 (which backported the
76
- // change from Node.js 19).
70
+ }
77
71
  const fromGlobal = (_a = globalThis
78
72
  .crypto) === null || _a === void 0 ? void 0 : _a.subtle;
79
73
  if (fromGlobal) {
80
74
  cachedSubtle = fromGlobal;
81
75
  return cachedSubtle;
82
76
  }
83
- // Fallback for Node.js 18.0–18.18, which ships Web Crypto via
84
- // `node:crypto` but does not expose it on `globalThis` by default.
85
- // Using `require` (rather than a static `import`) keeps the
86
- // node:crypto reference off the dependency graph of browser bundlers
87
- // that would otherwise fail to resolve it.
77
+ // Load Node's fallback only when needed so browser callers can use the
78
+ // global API without loading a Node module.
88
79
  try {
89
80
  /* eslint-disable @typescript-eslint/no-var-requires */
90
81
  const nodeCrypto = require("crypto");
@@ -104,8 +95,8 @@ async function getSubtle() {
104
95
  }
105
96
  function bytesToHex(bytes) {
106
97
  let hex = "";
107
- for (let i = 0; i < bytes.length; i++) {
108
- hex += bytes[i].toString(16).padStart(2, "0");
98
+ for (const byte of bytes) {
99
+ hex += byte.toString(16).padStart(2, "0");
109
100
  }
110
101
  return hex;
111
102
  }
@@ -113,8 +104,9 @@ function bytesToHex(bytes) {
113
104
  // the same length (callers enforce SHA256_HEX_LENGTH), so this purely
114
105
  // avoids early-exit on the first differing character.
115
106
  function timingSafeEqualHex(a, b) {
116
- if (a.length !== b.length)
107
+ if (a.length !== b.length) {
117
108
  return false;
109
+ }
118
110
  let diff = 0;
119
111
  for (let i = 0; i < a.length; i++) {
120
112
  diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/webhooks.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Helpers for receiving and verifying Notion webhook deliveries.\n *\n * Notion signs each webhook request with HMAC-SHA256 over the raw HTTP\n * body using the subscription's verification token as the key, and sends\n * the resulting hex digest in the `X-Notion-Signature` header as\n * `sha256=<hex>`. To verify a delivery, callers must pass the body\n * **exactly as it arrived over the wire** — any JSON re-serialization\n * will change the bytes and invalidate the signature.\n *\n * The helpers prefer the Web Crypto API (`globalThis.crypto.subtle`)\n * when present (browsers, edge runtimes, Node.js >= 18.19) and\n * transparently fall back to `node:crypto`'s `webcrypto.subtle` on older\n * Node.js 18 builds where `globalThis.crypto` is not yet enabled by\n * default. They work without configuration in Node.js, Bun, Deno,\n * Vercel Edge Functions, Cloudflare Workers, and modern browsers.\n */\n\nconst SIGNATURE_PREFIX = \"sha256=\"\nconst SHA256_HEX_LENGTH = 64\n\nexport type VerifyWebhookSignatureArgs = {\n /**\n * The raw HTTP request body — exactly as received, before any parsing.\n * Pass a string for text bodies or a Uint8Array/Buffer for binary-safe\n * access. Re-serialized JSON will not verify.\n */\n body: string | Uint8Array\n /**\n * The value of the `X-Notion-Signature` request header. Verification\n * fails (returns false) if this is missing or malformed.\n */\n signature: string | null | undefined\n /**\n * The verification token configured for this webhook subscription\n * (returned by Notion when the subscription was created and surfaced\n * during the initial handshake).\n */\n verificationToken: string\n}\n\n/**\n * Verify that a webhook delivery came from Notion and has not been\n * tampered with.\n *\n * Performs a constant-time comparison; returns `true` only if the\n * supplied `signature` matches HMAC-SHA256 of `body` keyed by\n * `verificationToken`. Returns `false` (rather than throwing) for any\n * malformed input so the caller can respond with a single 401/403 path.\n */\nexport async function verifyWebhookSignature(\n args: VerifyWebhookSignatureArgs\n): Promise<boolean> {\n const { body, signature, verificationToken } = args\n\n if (typeof signature !== \"string\") return false\n if (!signature.startsWith(SIGNATURE_PREFIX)) return false\n\n const providedHex = signature.slice(SIGNATURE_PREFIX.length).toLowerCase()\n if (providedHex.length !== SHA256_HEX_LENGTH) return false\n if (!/^[0-9a-f]+$/.test(providedHex)) return false\n\n const computedHex = await computeHmacSha256Hex(verificationToken, body)\n return timingSafeEqualHex(providedHex, computedHex)\n}\n\n/**\n * Compute the value Notion would send in `X-Notion-Signature` for a\n * given body and verification token. Useful for unit-testing webhook\n * handlers without standing up a real subscription.\n */\nexport async function signWebhookPayload(args: {\n body: string | Uint8Array\n verificationToken: string\n}): Promise<string> {\n const hex = await computeHmacSha256Hex(args.verificationToken, args.body)\n return `${SIGNATURE_PREFIX}${hex}`\n}\n\nasync function computeHmacSha256Hex(\n key: string,\n body: string | Uint8Array\n): Promise<string> {\n const subtle = await getSubtle()\n\n const encoder = new TextEncoder()\n const keyBytes = encoder.encode(key)\n // Copy any Uint8Array input into a fresh ArrayBuffer-backed view so\n // subtle.sign (which forbids SharedArrayBuffer-backed views) is\n // satisfied regardless of where the caller's buffer came from.\n const bodyBytes =\n typeof body === \"string\" ? encoder.encode(body) : Uint8Array.from(body)\n\n const cryptoKey = await subtle.importKey(\n \"raw\",\n keyBytes,\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"]\n )\n const signatureBuffer = await subtle.sign(\"HMAC\", cryptoKey, bodyBytes)\n return bytesToHex(new Uint8Array(signatureBuffer))\n}\n\nlet cachedSubtle: SubtleCrypto | undefined\n\nasync function getSubtle(): Promise<SubtleCrypto> {\n if (cachedSubtle) return cachedSubtle\n\n // Preferred path: every modern runtime exposes Web Crypto on the\n // global object. This includes browsers, Vercel Edge, Cloudflare\n // Workers, Deno, Bun, and Node.js >= 18.19 (which backported the\n // change from Node.js 19).\n const fromGlobal = (globalThis as { crypto?: { subtle?: SubtleCrypto } })\n .crypto?.subtle\n if (fromGlobal) {\n cachedSubtle = fromGlobal\n return cachedSubtle\n }\n\n // Fallback for Node.js 18.0–18.18, which ships Web Crypto via\n // `node:crypto` but does not expose it on `globalThis` by default.\n // Using `require` (rather than a static `import`) keeps the\n // node:crypto reference off the dependency graph of browser bundlers\n // that would otherwise fail to resolve it.\n try {\n /* eslint-disable @typescript-eslint/no-var-requires */\n const nodeCrypto = require(\"crypto\") as {\n webcrypto?: { subtle?: SubtleCrypto }\n }\n /* eslint-enable @typescript-eslint/no-var-requires */\n if (nodeCrypto.webcrypto?.subtle) {\n cachedSubtle = nodeCrypto.webcrypto.subtle\n return cachedSubtle\n }\n } catch {\n // node:crypto unavailable (e.g. a browser bundle that stubbed it).\n // Fall through to the error below.\n }\n\n throw new Error(\n \"verifyWebhookSignature requires Web Crypto support \" +\n \"(globalThis.crypto.subtle or node:crypto.webcrypto). Upgrade to \" +\n \"a runtime that provides one of them.\"\n )\n}\n\nfunction bytesToHex(bytes: Uint8Array): string {\n let hex = \"\"\n for (let i = 0; i < bytes.length; i++) {\n hex += (bytes[i] as number).toString(16).padStart(2, \"0\")\n }\n return hex\n}\n\n// Constant-time string comparison. The inputs are already known to be\n// the same length (callers enforce SHA256_HEX_LENGTH), so this purely\n// avoids early-exit on the first differing character.\nfunction timingSafeEqualHex(a: string, b: string): boolean {\n if (a.length !== b.length) return false\n let diff = 0\n for (let i = 0; i < a.length; i++) {\n diff |= a.charCodeAt(i) ^ b.charCodeAt(i)\n }\n return diff === 0\n}\n"]}
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/webhooks.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Helpers for receiving and verifying Notion webhook deliveries.\n *\n * Event signatures use HMAC-SHA256 with the subscription's verification\n * token. The `X-Notion-Signature` header contains `sha256=<hex>`.\n * Pass the raw body as received. Parsing and re-serializing JSON can change\n * its bytes and invalidate the signature.\n *\n * The helpers use `globalThis.crypto.subtle` when available, then fall\n * back to the Web Crypto API in Node's crypto module.\n */\n\nconst SIGNATURE_PREFIX = \"sha256=\"\nconst SHA256_HEX_LENGTH = 64\n\nexport type VerifyWebhookSignatureArgs = {\n /**\n * The raw HTTP request body, before any parsing.\n * Pass a string for text bodies or a Uint8Array/Buffer for binary-safe\n * access. Re-serialized JSON will not verify.\n */\n body: string | Uint8Array\n /**\n * The value of the `X-Notion-Signature` request header. Verification\n * fails (returns false) if this is missing or malformed.\n */\n signature: string | null | undefined\n /**\n * The verification token configured for this webhook subscription\n * (returned by Notion when the subscription was created and surfaced\n * during the initial handshake).\n */\n verificationToken: string\n}\n\n/**\n * Verify that a webhook delivery came from Notion and has not been\n * tampered with.\n *\n * Returns `true` if the signature matches HMAC-SHA256 of the body using\n * the verification token. Returns `false` for a missing or malformed\n * signature. Crypto errors may throw.\n */\nexport async function verifyWebhookSignature(\n args: VerifyWebhookSignatureArgs\n): Promise<boolean> {\n const { body, signature, verificationToken } = args\n\n if (typeof signature !== \"string\") {\n return false\n }\n if (!signature.startsWith(SIGNATURE_PREFIX)) {\n return false\n }\n\n const providedHex = signature.slice(SIGNATURE_PREFIX.length).toLowerCase()\n if (providedHex.length !== SHA256_HEX_LENGTH) {\n return false\n }\n if (!/^[0-9a-f]+$/.test(providedHex)) {\n return false\n }\n\n const computedHex = await computeHmacSha256Hex(verificationToken, body)\n return timingSafeEqualHex(providedHex, computedHex)\n}\n\n/**\n * Compute the value Notion would send in `X-Notion-Signature` for a\n * given body and verification token. Use this to test webhook handlers\n * without a live subscription.\n */\nexport async function signWebhookPayload(args: {\n body: string | Uint8Array\n verificationToken: string\n}): Promise<string> {\n const hex = await computeHmacSha256Hex(args.verificationToken, args.body)\n return `${SIGNATURE_PREFIX}${hex}`\n}\n\nasync function computeHmacSha256Hex(\n key: string,\n body: string | Uint8Array\n): Promise<string> {\n const subtle = await getSubtle()\n\n const encoder = new TextEncoder()\n const keyBytes = encoder.encode(key)\n // Copy any Uint8Array input into a fresh ArrayBuffer-backed view so\n // subtle.sign (which forbids SharedArrayBuffer-backed views) is\n // satisfied regardless of where the caller's buffer came from.\n const bodyBytes =\n typeof body === \"string\" ? encoder.encode(body) : Uint8Array.from(body)\n\n const cryptoKey = await subtle.importKey(\n \"raw\",\n keyBytes,\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"]\n )\n const signatureBuffer = await subtle.sign(\"HMAC\", cryptoKey, bodyBytes)\n return bytesToHex(new Uint8Array(signatureBuffer))\n}\n\nlet cachedSubtle: SubtleCrypto | undefined\n\nasync function getSubtle(): Promise<SubtleCrypto> {\n if (cachedSubtle) {\n return cachedSubtle\n }\n\n const fromGlobal = (globalThis as { crypto?: { subtle?: SubtleCrypto } })\n .crypto?.subtle\n if (fromGlobal) {\n cachedSubtle = fromGlobal\n return cachedSubtle\n }\n\n // Load Node's fallback only when needed so browser callers can use the\n // global API without loading a Node module.\n try {\n /* eslint-disable @typescript-eslint/no-var-requires */\n const nodeCrypto = require(\"crypto\") as {\n webcrypto?: { subtle?: SubtleCrypto }\n }\n /* eslint-enable @typescript-eslint/no-var-requires */\n if (nodeCrypto.webcrypto?.subtle) {\n cachedSubtle = nodeCrypto.webcrypto.subtle\n return cachedSubtle\n }\n } catch {\n // node:crypto unavailable (e.g. a browser bundle that stubbed it).\n // Fall through to the error below.\n }\n\n throw new Error(\n \"verifyWebhookSignature requires Web Crypto support \" +\n \"(globalThis.crypto.subtle or node:crypto.webcrypto). Upgrade to \" +\n \"a runtime that provides one of them.\"\n )\n}\n\nfunction bytesToHex(bytes: Uint8Array): string {\n let hex = \"\"\n for (const byte of bytes) {\n hex += byte.toString(16).padStart(2, \"0\")\n }\n return hex\n}\n\n// Constant-time string comparison. The inputs are already known to be\n// the same length (callers enforce SHA256_HEX_LENGTH), so this purely\n// avoids early-exit on the first differing character.\nfunction timingSafeEqualHex(a: string, b: string): boolean {\n if (a.length !== b.length) {\n return false\n }\n let diff = 0\n for (let i = 0; i < a.length; i++) {\n diff |= a.charCodeAt(i) ^ b.charCodeAt(i)\n }\n return diff === 0\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notionhq/client",
3
- "version": "5.26.0",
3
+ "version": "5.27.0",
4
4
  "description": "A simple and easy to use client for the Notion API",
5
5
  "engines": {
6
6
  "node": ">=18"
@@ -26,8 +26,9 @@
26
26
  "prepublishOnly": "npm run checkLoggedIn && npm run lint && npm run test",
27
27
  "build": "tsc",
28
28
  "prettier": "prettier --write .",
29
- "lint": "prettier --check . && eslint . --ext .ts && cspell '**/*' ",
29
+ "lint": "prettier --check . && eslint . --ext .ts,.js && cspell '**/*'",
30
30
  "test": "jest ./test",
31
+ "check:compatibility": "node build/test/checkCompatibility.js",
31
32
  "check-links": "git ls-files | grep md$ | xargs -n 1 markdown-link-check",
32
33
  "prebuild": "npm run clean",
33
34
  "clean": "rm -rf ./build",
@@ -35,7 +36,7 @@
35
36
  },
36
37
  "lint-staged": {
37
38
  "*.{ts,js,json,md}": "prettier --write",
38
- "*.ts": "eslint --fix"
39
+ "*.{ts,js}": "eslint --fix"
39
40
  },
40
41
  "author": "",
41
42
  "license": "MIT",