@notionhq/client 5.9.0 → 5.10.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.
package/README.md CHANGED
@@ -132,14 +132,55 @@ You may also set a custom `logger` to emit logs to a destination other than `std
132
132
 
133
133
  The `Client` supports the following options on initialization. These options are all keys in the single constructor parameter.
134
134
 
135
- | Option | Default value | Type | Description |
136
- | ----------- | -------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
137
- | `auth` | `undefined` | `string` | Bearer token for authentication. If left undefined, the `auth` parameter should be set on each request. |
138
- | `logLevel` | `LogLevel.WARN` | `LogLevel` | Verbosity of logs the instance will produce. By default, logs are written to `stdout`. |
139
- | `timeoutMs` | `60_000` | `number` | Number of milliseconds to wait before emitting a `RequestTimeoutError` |
140
- | `baseUrl` | `"https://api.notion.com"` | `string` | The root URL for sending API requests. This can be changed to test with a mock server. |
141
- | `logger` | Log to console | `Logger` | A custom logging function. This function is only called when the client emits a log that is equal or greater severity than `logLevel`. |
142
- | `agent` | Default node agent | `http.Agent` | Used to control creation of TCP sockets. A common use is to proxy requests with [`https-proxy-agent`](https://github.com/TooTallNate/node-https-proxy-agent) |
135
+ | Option | Default value | Type | Description |
136
+ | ----------- | -------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
137
+ | `auth` | `undefined` | `string` | Bearer token for authentication. If left undefined, the `auth` parameter should be set on each request. |
138
+ | `logLevel` | `LogLevel.WARN` | `LogLevel` | Verbosity of logs the instance will produce. By default, logs are written to `stdout`. |
139
+ | `timeoutMs` | `60_000` | `number` | Number of milliseconds to wait before emitting a `RequestTimeoutError` |
140
+ | `baseUrl` | `"https://api.notion.com"` | `string` | The root URL for sending API requests. This can be changed to test with a mock server. |
141
+ | `logger` | Log to console | `Logger` | A custom logging function. This function is only called when the client emits a log that is equal or greater severity than `logLevel`. |
142
+ | `agent` | Default node agent | `http.Agent` | Used to control creation of TCP sockets. A common use is to proxy requests with [`https-proxy-agent`](https://github.com/TooTallNate/node-https-proxy-agent) |
143
+ | `retry` | `{ maxRetries: 2 }` | `RetryOptions` | Configuration for automatic retries on rate limits (429) and server errors (500, 503). See [Automatic retries](#automatic-retries) below. |
144
+
145
+ ### Automatic retries
146
+
147
+ The client automatically retries requests that fail due to rate limiting or transient server errors. By default, it will retry up to 2 times using exponential back-off with jitter.
148
+
149
+ **Retryable errors:**
150
+
151
+ - `rate_limited` (HTTP 429) - Too many requests; retried for all HTTP methods
152
+ - `internal_server_error` (HTTP 500) - Server error; retried only for GET and DELETE
153
+ - `service_unavailable` (HTTP 503) - Service temporarily unavailable; retried only for GET and DELETE
154
+
155
+ Server errors (500, 503) are only retried for idempotent HTTP methods (GET, DELETE) to avoid duplicate side effects. Rate limits (429) are retried for all methods since the server explicitly asks clients to retry.
156
+
157
+ **Retry behavior:**
158
+
159
+ - Uses exponential back-off: delays increase with each retry attempt
160
+ - Respects the `Retry-After` header when present (both delta-seconds and HTTP-date formats)
161
+ - Adds random jitter to prevent thundering herd problems
162
+
163
+ **Configuration:**
164
+
165
+ ```js
166
+ const notion = new Client({
167
+ auth: process.env.NOTION_TOKEN,
168
+ retry: {
169
+ maxRetries: 5, // Maximum retry attempts (default: 2)
170
+ initialRetryDelayMs: 500, // Initial delay between retries (default: 1000ms)
171
+ maxRetryDelayMs: 60000, // Maximum delay between retries (default: 60000ms)
172
+ },
173
+ })
174
+ ```
175
+
176
+ To disable automatic retries:
177
+
178
+ ```js
179
+ const notion = new Client({
180
+ auth: process.env.NOTION_TOKEN,
181
+ retry: false,
182
+ })
183
+ ```
143
184
 
144
185
  ### TypeScript
145
186
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notionhq/client",
3
- "version": "5.9.0",
3
+ "version": "5.10.0",
4
4
  "description": "A simple and easy to use client for the Notion API",
5
5
  "engines": {
6
6
  "node": ">=18"
@@ -44,17 +44,17 @@
44
44
  "build/src/**"
45
45
  ],
46
46
  "devDependencies": {
47
- "@types/jest": "28.1.4",
48
- "@typescript-eslint/eslint-plugin": "5.39.0",
49
- "@typescript-eslint/parser": "5.39.0",
50
- "cspell": "5.4.1",
51
- "eslint": "7.24.0",
47
+ "@types/jest": "29.5.14",
48
+ "@typescript-eslint/eslint-plugin": "7.18.0",
49
+ "@typescript-eslint/parser": "7.18.0",
50
+ "cspell": "8.17.1",
51
+ "eslint": "8.57.1",
52
52
  "husky": "^9.1.7",
53
- "jest": "28.1.2",
53
+ "jest": "29.7.0",
54
54
  "lint-staged": "^16.2.6",
55
55
  "markdown-link-check": "3.13.7",
56
- "prettier": "2.8.8",
57
- "ts-jest": "28.0.5",
56
+ "prettier": "3.3.3",
57
+ "ts-jest": "29.2.5",
58
58
  "typescript": "5.9.2"
59
59
  }
60
60
  }
@@ -2,7 +2,25 @@ import type { Agent } from "node:http";
2
2
  import { type Logger, LogLevel } from "./logging";
3
3
  import { type GetBlockParameters, type GetBlockResponse, type UpdateBlockParameters, type UpdateBlockResponse, type DeleteBlockParameters, type DeleteBlockResponse, type AppendBlockChildrenParameters, type AppendBlockChildrenResponse, type ListBlockChildrenParameters, type ListBlockChildrenResponse, type QueryDataSourceParameters, type QueryDataSourceResponse, type CreateDataSourceParameters, type CreateDataSourceResponse, type UpdateDataSourceParameters, type UpdateDataSourceResponse, type GetDataSourceParameters, type GetDataSourceResponse, type CreatePageParameters, type CreatePageResponse, type GetPageParameters, type GetPageResponse, type UpdatePageParameters, type UpdatePageResponse, type MovePageParameters, type MovePageResponse, type GetUserParameters, type GetUserResponse, type ListUsersParameters, type ListUsersResponse, type SearchParameters, type SearchResponse, type GetSelfParameters, type GetSelfResponse, type GetPagePropertyParameters, type GetPagePropertyResponse, type CreateCommentParameters, type CreateCommentResponse, type ListCommentsParameters, type ListCommentsResponse, type GetCommentParameters, type GetCommentResponse, type OauthTokenResponse, type OauthTokenParameters, type OauthIntrospectResponse, type OauthIntrospectParameters, type OauthRevokeResponse, type OauthRevokeParameters, type CreateFileUploadParameters, type CreateFileUploadResponse, type GetFileUploadResponse, type GetFileUploadParameters, type SendFileUploadParameters, type SendFileUploadResponse, type CompleteFileUploadParameters, type CompleteFileUploadResponse, type ListFileUploadsParameters, type ListFileUploadsResponse, GetDatabaseParameters, GetDatabaseResponse, CreateDatabaseResponse, CreateDatabaseParameters, UpdateDatabaseParameters, UpdateDatabaseResponse, ListDataSourceTemplatesResponse, ListDataSourceTemplatesParameters } from "./api-endpoints";
4
4
  import type { SupportedFetch } from "./fetch-types";
5
- export interface ClientOptions {
5
+ export type RetryOptions = {
6
+ /**
7
+ * Maximum number of retry attempts. Set to 0 to disable retries.
8
+ * @default 2
9
+ */
10
+ maxRetries?: number;
11
+ /**
12
+ * Initial delay between retries in milliseconds.
13
+ * Used as base for exponential back-off when retry-after header is absent.
14
+ * @default 1000
15
+ */
16
+ initialRetryDelayMs?: number;
17
+ /**
18
+ * Maximum delay between retries in milliseconds.
19
+ * @default 60000
20
+ */
21
+ maxRetryDelayMs?: number;
22
+ };
23
+ export type ClientOptions = {
6
24
  auth?: string;
7
25
  timeoutMs?: number;
8
26
  baseUrl?: string;
@@ -12,12 +30,17 @@ export interface ClientOptions {
12
30
  fetch?: SupportedFetch;
13
31
  /** Silently ignored in the browser */
14
32
  agent?: Agent;
15
- }
33
+ /**
34
+ * Configuration for automatic retries on rate limit (429) and server errors.
35
+ * Set to false to disable retries entirely.
36
+ */
37
+ retry?: RetryOptions | false;
38
+ };
16
39
  type FileParam = {
17
40
  filename?: string;
18
41
  data: string | Blob;
19
42
  };
20
- export interface RequestParameters {
43
+ export type RequestParameters = {
21
44
  path: string;
22
45
  method: Method;
23
46
  query?: QueryParams;
@@ -33,7 +56,7 @@ export interface RequestParameters {
33
56
  client_id: string;
34
57
  client_secret: string;
35
58
  };
36
- }
59
+ };
37
60
  export default class Client {
38
61
  #private;
39
62
  static readonly defaultNotionVersion = "2025-09-03";
@@ -42,6 +65,63 @@ export default class Client {
42
65
  * Sends a request.
43
66
  */
44
67
  request<ResponseBody extends object>(args: RequestParameters): Promise<ResponseBody>;
68
+ /**
69
+ * Builds the full URL with query parameters.
70
+ */
71
+ private buildRequestUrl;
72
+ /**
73
+ * Serializes the request body to JSON string if non-empty.
74
+ */
75
+ private serializeBody;
76
+ /**
77
+ * Builds the request headers including auth and content-type.
78
+ */
79
+ private buildRequestHeaders;
80
+ /**
81
+ * Builds the authorization header based on auth type.
82
+ */
83
+ private buildAuthHeader;
84
+ /**
85
+ * Builds FormData from form parameters if provided.
86
+ * Also removes content-type header to let fetch set the boundary.
87
+ */
88
+ private buildFormData;
89
+ /**
90
+ * Executes the request with retry logic.
91
+ */
92
+ private executeWithRetry;
93
+ /**
94
+ * Executes a single HTTP request (no retry).
95
+ */
96
+ private executeSingleRequest;
97
+ /**
98
+ * Logs a request error with appropriate detail level.
99
+ */
100
+ private logRequestError;
101
+ /**
102
+ * Extracts request_id from an object if present.
103
+ */
104
+ private extractRequestId;
105
+ /**
106
+ * Determines if an error can be retried based on its error code and method.
107
+ * Rate limits (429) are always retryable since the server explicitly asks us
108
+ * to retry. Server errors (500, 503) are only retried for idempotent methods
109
+ * (GET, DELETE) to avoid duplicate side effects.
110
+ */
111
+ private canRetry;
112
+ /**
113
+ * Calculates the delay before the next retry attempt.
114
+ * Uses retry-after header if present, otherwise exponential back-off with
115
+ * jitter.
116
+ */
117
+ private calculateRetryDelay;
118
+ /**
119
+ * Parses the retry-after header value.
120
+ * Supports both delta-seconds (e.g., "120") and HTTP-date formats.
121
+ * Returns the delay in milliseconds, or undefined if not present or invalid.
122
+ */
123
+ private parseRetryAfterHeader;
124
+ private sleep;
45
125
  readonly blocks: {
46
126
  /**
47
127
  * Retrieve block
@@ -1 +1 @@
1
- {"version":3,"file":"Client.d.ts","sourceRoot":"","sources":["../../src/Client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Client.d.ts","sourceRoot":"","sources":["../../src/Client.ts"],"names":[],"mappings":"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"}
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _Client_auth, _Client_logLevel, _Client_logger, _Client_prefixUrl, _Client_timeoutMs, _Client_notionVersion, _Client_fetch, _Client_agent, _Client_userAgent;
13
+ var _Client_auth, _Client_logLevel, _Client_logger, _Client_prefixUrl, _Client_timeoutMs, _Client_notionVersion, _Client_fetch, _Client_agent, _Client_userAgent, _Client_maxRetries, _Client_initialRetryDelayMs, _Client_maxRetryDelayMs;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const logging_1 = require("./logging");
16
16
  const errors_1 = require("./errors");
@@ -19,7 +19,7 @@ const api_endpoints_1 = require("./api-endpoints");
19
19
  const package_json_1 = require("../package.json");
20
20
  class Client {
21
21
  constructor(options) {
22
- var _a, _b, _c, _d, _e, _f;
22
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
23
23
  _Client_auth.set(this, void 0);
24
24
  _Client_logLevel.set(this, void 0);
25
25
  _Client_logger.set(this, void 0);
@@ -29,6 +29,9 @@ class Client {
29
29
  _Client_fetch.set(this, void 0);
30
30
  _Client_agent.set(this, void 0);
31
31
  _Client_userAgent.set(this, void 0);
32
+ _Client_maxRetries.set(this, void 0);
33
+ _Client_initialRetryDelayMs.set(this, void 0);
34
+ _Client_maxRetryDelayMs.set(this, void 0);
32
35
  /*
33
36
  * Notion API endpoints
34
37
  */
@@ -474,6 +477,16 @@ class Client {
474
477
  __classPrivateFieldSet(this, _Client_fetch, (_f = options === null || options === void 0 ? void 0 : options.fetch) !== null && _f !== void 0 ? _f : fetch, "f");
475
478
  __classPrivateFieldSet(this, _Client_agent, options === null || options === void 0 ? void 0 : options.agent, "f");
476
479
  __classPrivateFieldSet(this, _Client_userAgent, `notionhq-client/${package_json_1.version}`, "f");
480
+ if ((options === null || options === void 0 ? void 0 : options.retry) === false) {
481
+ __classPrivateFieldSet(this, _Client_maxRetries, 0, "f");
482
+ __classPrivateFieldSet(this, _Client_initialRetryDelayMs, 0, "f");
483
+ __classPrivateFieldSet(this, _Client_maxRetryDelayMs, 0, "f");
484
+ }
485
+ else {
486
+ __classPrivateFieldSet(this, _Client_maxRetries, (_h = (_g = options === null || options === void 0 ? void 0 : options.retry) === null || _g === void 0 ? void 0 : _g.maxRetries) !== null && _h !== void 0 ? _h : 2, "f");
487
+ __classPrivateFieldSet(this, _Client_initialRetryDelayMs, (_k = (_j = options === null || options === void 0 ? void 0 : options.retry) === null || _j === void 0 ? void 0 : _j.initialRetryDelayMs) !== null && _k !== void 0 ? _k : 1000, "f");
488
+ __classPrivateFieldSet(this, _Client_maxRetryDelayMs, (_m = (_l = options === null || options === void 0 ? void 0 : options.retry) === null || _l === void 0 ? void 0 : _l.maxRetryDelayMs) !== null && _m !== void 0 ? _m : 60000, "f");
489
+ }
477
490
  }
478
491
  /**
479
492
  * Sends a request.
@@ -482,10 +495,22 @@ class Client {
482
495
  const { path, method, query, body, formDataParams, auth } = args;
483
496
  (0, errors_1.validateRequestPath)(path);
484
497
  this.log(logging_1.LogLevel.INFO, "request start", { method, path });
485
- // If the body is empty, don't send the body in the HTTP request
486
- const bodyAsJsonString = !body || Object.entries(body).length === 0
487
- ? undefined
488
- : JSON.stringify(body);
498
+ const url = this.buildRequestUrl(path, query);
499
+ const bodyAsJsonString = this.serializeBody(body);
500
+ const headers = this.buildRequestHeaders(args.headers, auth, bodyAsJsonString);
501
+ const formData = this.buildFormData(formDataParams, headers);
502
+ return this.executeWithRetry({
503
+ url,
504
+ method,
505
+ path,
506
+ headers,
507
+ body: bodyAsJsonString !== null && bodyAsJsonString !== void 0 ? bodyAsJsonString : formData,
508
+ });
509
+ }
510
+ /**
511
+ * Builds the full URL with query parameters.
512
+ */
513
+ buildRequestUrl(path, query) {
489
514
  const url = new URL(`${__classPrivateFieldGet(this, _Client_prefixUrl, "f")}${path}`);
490
515
  if (query) {
491
516
  for (const [key, value] of Object.entries(query)) {
@@ -501,25 +526,24 @@ class Client {
501
526
  }
502
527
  }
503
528
  }
504
- // Allow both client ID / client secret based auth as well as token based auth.
505
- let authorizationHeader;
506
- if (typeof auth === "object") {
507
- // Client ID and secret based auth is **ONLY** supported when using the
508
- // `/oauth/token` endpoint. If this is the case, handle formatting the
509
- // authorization header as required by `Basic` auth.
510
- const unencodedCredential = `${auth.client_id}:${auth.client_secret}`;
511
- const encodedCredential = Buffer.from(unencodedCredential).toString("base64");
512
- authorizationHeader = { authorization: `Basic ${encodedCredential}` };
513
- }
514
- else {
515
- // Otherwise format authorization header as `Bearer` token auth.
516
- authorizationHeader = this.authAsHeaders(auth);
529
+ return url;
530
+ }
531
+ /**
532
+ * Serializes the request body to JSON string if non-empty.
533
+ */
534
+ serializeBody(body) {
535
+ if (!body || Object.entries(body).length === 0) {
536
+ return undefined;
517
537
  }
538
+ return JSON.stringify(body);
539
+ }
540
+ /**
541
+ * Builds the request headers including auth and content-type.
542
+ */
543
+ buildRequestHeaders(customHeaders, auth, bodyAsJsonString) {
544
+ const authorizationHeader = this.buildAuthHeader(auth);
518
545
  const headers = {
519
- // Request-level custom additional headers can be provided, but
520
- // don't allow them to override all other headers, e.g. the
521
- // standard user agent.
522
- ...args.headers,
546
+ ...customHeaders,
523
547
  ...authorizationHeader,
524
548
  "Notion-Version": __classPrivateFieldGet(this, _Client_notionVersion, "f"),
525
549
  "user-agent": __classPrivateFieldGet(this, _Client_userAgent, "f"),
@@ -527,62 +551,208 @@ class Client {
527
551
  if (bodyAsJsonString !== undefined) {
528
552
  headers["content-type"] = "application/json";
529
553
  }
530
- let formData;
531
- if (formDataParams) {
532
- delete headers["content-type"];
533
- formData = new FormData();
534
- for (const [key, value] of Object.entries(formDataParams)) {
535
- if (typeof value === "string") {
536
- formData.append(key, value);
537
- }
538
- else if (typeof value === "object") {
539
- formData.append(key, typeof value.data === "object"
540
- ? value.data
541
- : new Blob([value.data]), value.filename);
542
- }
543
- }
554
+ return headers;
555
+ }
556
+ /**
557
+ * Builds the authorization header based on auth type.
558
+ */
559
+ buildAuthHeader(auth) {
560
+ if (typeof auth === "object") {
561
+ const unencodedCredential = `${auth.client_id}:${auth.client_secret}`;
562
+ const encodedCredential = Buffer.from(unencodedCredential).toString("base64");
563
+ return { authorization: `Basic ${encodedCredential}` };
564
+ }
565
+ return this.authAsHeaders(auth);
566
+ }
567
+ /**
568
+ * Builds FormData from form parameters if provided.
569
+ * Also removes content-type header to let fetch set the boundary.
570
+ */
571
+ buildFormData(formDataParams, headers) {
572
+ if (!formDataParams) {
573
+ return undefined;
544
574
  }
545
- try {
546
- const response = await errors_1.RequestTimeoutError.rejectAfterTimeout(__classPrivateFieldGet(this, _Client_fetch, "f").call(this, url.toString(), {
547
- method: method.toUpperCase(),
548
- headers,
549
- body: bodyAsJsonString !== null && bodyAsJsonString !== void 0 ? bodyAsJsonString : formData,
550
- agent: __classPrivateFieldGet(this, _Client_agent, "f"),
551
- }), __classPrivateFieldGet(this, _Client_timeoutMs, "f"));
552
- const responseText = await response.text();
553
- if (!response.ok) {
554
- throw (0, errors_1.buildRequestError)(response, responseText);
575
+ delete headers["content-type"];
576
+ const formData = new FormData();
577
+ for (const [key, value] of Object.entries(formDataParams)) {
578
+ if (typeof value === "string") {
579
+ formData.append(key, value);
580
+ }
581
+ else if (typeof value === "object") {
582
+ formData.append(key, typeof value.data === "object" ? value.data : new Blob([value.data]), value.filename);
555
583
  }
556
- const responseJson = JSON.parse(responseText);
557
- this.log(logging_1.LogLevel.INFO, "request success", {
558
- method,
559
- path,
560
- ...("request_id" in responseJson && responseJson.request_id
561
- ? { requestId: responseJson.request_id }
562
- : {}),
563
- });
564
- return responseJson;
565
584
  }
566
- catch (error) {
567
- if (!(0, errors_1.isNotionClientError)(error)) {
585
+ return formData;
586
+ }
587
+ /**
588
+ * Executes the request with retry logic.
589
+ */
590
+ async executeWithRetry(args) {
591
+ const { url, method, path, headers, body } = args;
592
+ let attempt = 0;
593
+ // eslint-disable-next-line no-constant-condition
594
+ while (true) {
595
+ try {
596
+ return await this.executeSingleRequest({
597
+ url,
598
+ method,
599
+ path,
600
+ headers,
601
+ body,
602
+ });
603
+ }
604
+ catch (error) {
605
+ if (!(0, errors_1.isNotionClientError)(error)) {
606
+ throw error;
607
+ }
608
+ this.logRequestError(error, attempt);
609
+ if (attempt < __classPrivateFieldGet(this, _Client_maxRetries, "f") && this.canRetry(error, method)) {
610
+ const delayMs = this.calculateRetryDelay(error, attempt);
611
+ this.log(logging_1.LogLevel.INFO, "retrying request", {
612
+ method,
613
+ path,
614
+ attempt: attempt + 1,
615
+ delayMs,
616
+ });
617
+ await this.sleep(delayMs);
618
+ attempt++;
619
+ continue;
620
+ }
568
621
  throw error;
569
622
  }
570
- // Log the error if it's one of our known error types
571
- this.log(logging_1.LogLevel.WARN, "request fail", {
572
- code: error.code,
573
- message: error.message,
574
- ...("request_id" in error && error.request_id
575
- ? { requestId: error.request_id }
576
- : {}),
623
+ }
624
+ }
625
+ /**
626
+ * Executes a single HTTP request (no retry).
627
+ */
628
+ async executeSingleRequest(args) {
629
+ const { url, method, path, headers, body } = args;
630
+ const response = await errors_1.RequestTimeoutError.rejectAfterTimeout(__classPrivateFieldGet(this, _Client_fetch, "f").call(this, url.toString(), {
631
+ method: method.toUpperCase(),
632
+ headers,
633
+ body,
634
+ agent: __classPrivateFieldGet(this, _Client_agent, "f"),
635
+ }), __classPrivateFieldGet(this, _Client_timeoutMs, "f"));
636
+ const responseText = await response.text();
637
+ if (!response.ok) {
638
+ throw (0, errors_1.buildRequestError)(response, responseText);
639
+ }
640
+ const responseJson = JSON.parse(responseText);
641
+ this.log(logging_1.LogLevel.INFO, "request success", {
642
+ method,
643
+ path,
644
+ ...this.extractRequestId(responseJson),
645
+ });
646
+ return responseJson;
647
+ }
648
+ /**
649
+ * Logs a request error with appropriate detail level.
650
+ */
651
+ logRequestError(error, attempt) {
652
+ this.log(logging_1.LogLevel.WARN, "request fail", {
653
+ code: error.code,
654
+ message: error.message,
655
+ attempt,
656
+ ...this.extractRequestId(error),
657
+ });
658
+ if ((0, errors_1.isHTTPResponseError)(error)) {
659
+ this.log(logging_1.LogLevel.DEBUG, "failed response body", {
660
+ body: error.body,
577
661
  });
578
- if ((0, errors_1.isHTTPResponseError)(error)) {
579
- // The response body may contain sensitive information so it is logged separately at the DEBUG level
580
- this.log(logging_1.LogLevel.DEBUG, "failed response body", {
581
- body: error.body,
582
- });
662
+ }
663
+ }
664
+ /**
665
+ * Extracts request_id from an object if present.
666
+ */
667
+ extractRequestId(obj) {
668
+ if (obj &&
669
+ typeof obj === "object" &&
670
+ "request_id" in obj &&
671
+ typeof obj.request_id === "string") {
672
+ return { requestId: obj.request_id };
673
+ }
674
+ return {};
675
+ }
676
+ /**
677
+ * Determines if an error can be retried based on its error code and method.
678
+ * Rate limits (429) are always retryable since the server explicitly asks us
679
+ * to retry. Server errors (500, 503) are only retried for idempotent methods
680
+ * (GET, DELETE) to avoid duplicate side effects.
681
+ */
682
+ canRetry(error, method) {
683
+ if (!errors_1.APIResponseError.isAPIResponseError(error)) {
684
+ return false;
685
+ }
686
+ // Rate limits are always retryable - server says "try again later"
687
+ if (error.code === errors_1.APIErrorCode.RateLimited) {
688
+ return true;
689
+ }
690
+ // Server errors only retry for idempotent methods
691
+ const isIdempotent = method === "get" || method === "delete";
692
+ if (isIdempotent) {
693
+ return (error.code === errors_1.APIErrorCode.InternalServerError ||
694
+ error.code === errors_1.APIErrorCode.ServiceUnavailable);
695
+ }
696
+ return false;
697
+ }
698
+ /**
699
+ * Calculates the delay before the next retry attempt.
700
+ * Uses retry-after header if present, otherwise exponential back-off with
701
+ * jitter.
702
+ */
703
+ calculateRetryDelay(error, attempt) {
704
+ // Try to get retry-after from the error headers
705
+ if (errors_1.APIResponseError.isAPIResponseError(error)) {
706
+ const retryAfterMs = this.parseRetryAfterHeader(error.headers);
707
+ if (retryAfterMs !== undefined) {
708
+ return Math.min(retryAfterMs, __classPrivateFieldGet(this, _Client_maxRetryDelayMs, "f"));
583
709
  }
584
- throw error;
585
710
  }
711
+ // Exponential back-off with full jitter
712
+ const baseDelay = __classPrivateFieldGet(this, _Client_initialRetryDelayMs, "f") * Math.pow(2, attempt);
713
+ const jitter = Math.random();
714
+ return Math.min(baseDelay * jitter + baseDelay / 2, __classPrivateFieldGet(this, _Client_maxRetryDelayMs, "f"));
715
+ }
716
+ /**
717
+ * Parses the retry-after header value.
718
+ * Supports both delta-seconds (e.g., "120") and HTTP-date formats.
719
+ * Returns the delay in milliseconds, or undefined if not present or invalid.
720
+ */
721
+ parseRetryAfterHeader(headers) {
722
+ var _a, _b;
723
+ if (!headers) {
724
+ return undefined;
725
+ }
726
+ let retryAfterValue = null;
727
+ // Handle Headers object (standard fetch API)
728
+ if (typeof headers === "object" && "get" in headers) {
729
+ const headersObj = headers;
730
+ retryAfterValue = headersObj.get("retry-after");
731
+ }
732
+ // Handle plain object
733
+ else if (typeof headers === "object") {
734
+ const headersRecord = headers;
735
+ retryAfterValue =
736
+ (_b = (_a = headersRecord["retry-after"]) !== null && _a !== void 0 ? _a : headersRecord["Retry-After"]) !== null && _b !== void 0 ? _b : null;
737
+ }
738
+ if (!retryAfterValue) {
739
+ return undefined;
740
+ }
741
+ // Try parsing as delta-seconds (integer)
742
+ const seconds = parseInt(retryAfterValue, 10);
743
+ if (!isNaN(seconds) && seconds >= 0) {
744
+ return seconds * 1000;
745
+ }
746
+ // Try parsing as HTTP-date
747
+ const date = Date.parse(retryAfterValue);
748
+ if (!isNaN(date)) {
749
+ const delayMs = date - Date.now();
750
+ return delayMs > 0 ? delayMs : 0;
751
+ }
752
+ return undefined;
753
+ }
754
+ sleep(ms) {
755
+ return new Promise(resolve => setTimeout(resolve, ms));
586
756
  }
587
757
  /**
588
758
  * Emits a log message to the console.
@@ -613,7 +783,7 @@ class Client {
613
783
  return headers;
614
784
  }
615
785
  }
616
- _Client_auth = new WeakMap(), _Client_logLevel = new WeakMap(), _Client_logger = new WeakMap(), _Client_prefixUrl = new WeakMap(), _Client_timeoutMs = new WeakMap(), _Client_notionVersion = new WeakMap(), _Client_fetch = new WeakMap(), _Client_agent = new WeakMap(), _Client_userAgent = new WeakMap();
786
+ _Client_auth = new WeakMap(), _Client_logLevel = new WeakMap(), _Client_logger = new WeakMap(), _Client_prefixUrl = new WeakMap(), _Client_timeoutMs = new WeakMap(), _Client_notionVersion = new WeakMap(), _Client_fetch = new WeakMap(), _Client_agent = new WeakMap(), _Client_userAgent = new WeakMap(), _Client_maxRetries = new WeakMap(), _Client_initialRetryDelayMs = new WeakMap(), _Client_maxRetryDelayMs = new WeakMap();
617
787
  Client.defaultNotionVersion = "2025-09-03";
618
788
  exports.default = Client;
619
789
  //# sourceMappingURL=Client.js.map