@visus-io/notion-sdk-ts 3.0.2 → 3.1.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.
Files changed (130) hide show
  1. package/README.md +20 -87
  2. package/dist/api/asyncTasks.api.d.ts +72 -0
  3. package/dist/api/asyncTasks.api.js +70 -0
  4. package/dist/api/base.api.d.ts +15 -4
  5. package/dist/api/base.api.js +20 -8
  6. package/dist/api/blocks.api.d.ts +435 -73
  7. package/dist/api/blocks.api.js +43 -1
  8. package/dist/api/comments.api.d.ts +42 -5
  9. package/dist/api/comments.api.js +45 -1
  10. package/dist/api/customEmojis.api.d.ts +38 -0
  11. package/dist/api/customEmojis.api.js +38 -0
  12. package/dist/api/dataSources.api.d.ts +67 -14
  13. package/dist/api/dataSources.api.js +26 -1
  14. package/dist/api/databases.api.d.ts +47 -11
  15. package/dist/api/databases.api.js +4 -1
  16. package/dist/api/fileUploads.api.d.ts +8 -5
  17. package/dist/api/fileUploads.api.js +11 -7
  18. package/dist/api/index.d.ts +3 -0
  19. package/dist/api/index.js +7 -1
  20. package/dist/api/pages.api.d.ts +144 -10
  21. package/dist/api/pages.api.js +66 -0
  22. package/dist/api/search.api.d.ts +12 -2
  23. package/dist/api/search.api.js +5 -2
  24. package/dist/api/users.api.d.ts +3 -0
  25. package/dist/api/users.api.js +2 -0
  26. package/dist/api/views.api.d.ts +286 -0
  27. package/dist/api/views.api.js +172 -0
  28. package/dist/client.d.ts +17 -17
  29. package/dist/client.js +25 -30
  30. package/dist/errors.d.ts +19 -5
  31. package/dist/errors.js +16 -4
  32. package/dist/helpers/block.helpers.d.ts +49 -5
  33. package/dist/helpers/block.helpers.js +50 -6
  34. package/dist/helpers/file.helpers.d.ts +46 -5
  35. package/dist/helpers/file.helpers.js +36 -8
  36. package/dist/helpers/filter.helpers.d.ts +8 -6
  37. package/dist/helpers/filter.helpers.js +2 -0
  38. package/dist/helpers/index.d.ts +3 -2
  39. package/dist/helpers/index.js +5 -1
  40. package/dist/helpers/pagination.helpers.d.ts +85 -13
  41. package/dist/helpers/pagination.helpers.js +114 -8
  42. package/dist/helpers/parent.helpers.d.ts +5 -3
  43. package/dist/helpers/parent.helpers.js +5 -3
  44. package/dist/helpers/property.helpers.d.ts +31 -0
  45. package/dist/helpers/property.helpers.js +30 -1
  46. package/dist/helpers/richText.helpers.d.ts +10 -5
  47. package/dist/helpers/richText.helpers.js +11 -6
  48. package/dist/helpers/sort.helpers.d.ts +2 -0
  49. package/dist/helpers/sort.helpers.js +2 -0
  50. package/dist/helpers/webhook.helpers.d.ts +54 -0
  51. package/dist/helpers/webhook.helpers.js +83 -0
  52. package/dist/models/asyncTask.model.d.ts +61 -0
  53. package/dist/models/asyncTask.model.js +91 -0
  54. package/dist/models/base.model.d.ts +16 -4
  55. package/dist/models/base.model.js +17 -5
  56. package/dist/models/block.model.d.ts +6 -2
  57. package/dist/models/block.model.js +48 -33
  58. package/dist/models/comment.model.d.ts +4 -2
  59. package/dist/models/comment.model.js +4 -2
  60. package/dist/models/customEmoji.model.d.ts +30 -0
  61. package/dist/models/customEmoji.model.js +44 -0
  62. package/dist/models/dataSource.model.d.ts +7 -5
  63. package/dist/models/dataSource.model.js +5 -3
  64. package/dist/models/database.model.d.ts +13 -5
  65. package/dist/models/database.model.js +15 -5
  66. package/dist/models/fileUpload.model.d.ts +6 -4
  67. package/dist/models/fileUpload.model.js +6 -4
  68. package/dist/models/index.d.ts +3 -0
  69. package/dist/models/index.js +7 -1
  70. package/dist/models/page.model.d.ts +8 -2
  71. package/dist/models/page.model.js +14 -4
  72. package/dist/models/richText.model.d.ts +3 -1
  73. package/dist/models/richText.model.js +3 -1
  74. package/dist/models/user.model.d.ts +4 -2
  75. package/dist/models/user.model.js +4 -2
  76. package/dist/models/view.model.d.ts +81 -0
  77. package/dist/models/view.model.js +121 -0
  78. package/dist/notion.d.ts +32 -8
  79. package/dist/notion.js +25 -4
  80. package/dist/schemas/asyncTask.schema.d.ts +53 -0
  81. package/dist/schemas/asyncTask.schema.js +88 -0
  82. package/dist/schemas/block.schema.d.ts +390 -73
  83. package/dist/schemas/block.schema.js +39 -8
  84. package/dist/schemas/codeLanguages.d.ts +7 -1
  85. package/dist/schemas/codeLanguages.js +4 -1
  86. package/dist/schemas/colors.d.ts +7 -1
  87. package/dist/schemas/colors.js +4 -1
  88. package/dist/schemas/comment.schema.d.ts +28 -5
  89. package/dist/schemas/comment.schema.js +11 -2
  90. package/dist/schemas/customEmoji.schema.d.ts +18 -0
  91. package/dist/schemas/customEmoji.schema.js +50 -0
  92. package/dist/schemas/dataSource.schema.d.ts +84 -10
  93. package/dist/schemas/dataSource.schema.js +31 -6
  94. package/dist/schemas/database.schema.d.ts +51 -7
  95. package/dist/schemas/database.schema.js +10 -3
  96. package/dist/schemas/emoji.schema.d.ts +7 -2
  97. package/dist/schemas/emoji.schema.js +4 -2
  98. package/dist/schemas/file.schema.d.ts +18 -2
  99. package/dist/schemas/file.schema.js +6 -2
  100. package/dist/schemas/fileUpload.schema.d.ts +9 -3
  101. package/dist/schemas/fileUpload.schema.js +5 -2
  102. package/dist/schemas/icon.schema.d.ts +116 -0
  103. package/dist/schemas/icon.schema.js +100 -0
  104. package/dist/schemas/index.d.ts +6 -0
  105. package/dist/schemas/index.js +6 -0
  106. package/dist/schemas/meetingNotesQuery.schema.d.ts +4198 -0
  107. package/dist/schemas/meetingNotesQuery.schema.js +67 -0
  108. package/dist/schemas/page.schema.d.ts +51 -9
  109. package/dist/schemas/page.schema.js +6 -2
  110. package/dist/schemas/pageMarkdown.schema.d.ts +70 -0
  111. package/dist/schemas/pageMarkdown.schema.js +70 -0
  112. package/dist/schemas/pageProperties.schema.d.ts +105 -21
  113. package/dist/schemas/pageProperties.schema.js +8 -6
  114. package/dist/schemas/pagination.schema.d.ts +57 -7
  115. package/dist/schemas/pagination.schema.js +25 -1
  116. package/dist/schemas/parent.schema.d.ts +39 -3
  117. package/dist/schemas/parent.schema.js +17 -5
  118. package/dist/schemas/propertyObjects.schema.d.ts +93 -15
  119. package/dist/schemas/propertyObjects.schema.js +11 -5
  120. package/dist/schemas/richText.schema.d.ts +23 -6
  121. package/dist/schemas/richText.schema.js +7 -4
  122. package/dist/schemas/shared.schema.d.ts +6 -3
  123. package/dist/schemas/shared.schema.js +6 -3
  124. package/dist/schemas/user.schema.d.ts +17 -0
  125. package/dist/schemas/user.schema.js +7 -3
  126. package/dist/schemas/view.schema.d.ts +1111 -0
  127. package/dist/schemas/view.schema.js +134 -0
  128. package/dist/validation.d.ts +11 -4
  129. package/dist/validation.js +11 -4
  130. package/package.json +6 -3
@@ -1,10 +1,10 @@
1
1
  import type { PaginatedList } from '../schemas';
2
2
  /**
3
- * Pagination helper utilities for collecting all results from paginated Notion API endpoints.
3
+ * Pagination helpers that collect all results from paginated Notion API endpoints.
4
4
  *
5
- * The Notion API uses cursor-based pagination. All list endpoints return a `PaginatedList<T>`
6
- * with `results`, `next_cursor`, and `has_more` properties. These helpers automate the process
7
- * of fetching all pages.
5
+ * The Notion API uses cursor-based pagination. Each list endpoint returns a
6
+ * `PaginatedList<T>` object with `results`, `next_cursor`, and `has_more` properties.
7
+ * These helpers fetch every page automatically.
8
8
  *
9
9
  * @example
10
10
  * ```typescript
@@ -35,14 +35,16 @@ import type { PaginatedList } from '../schemas';
35
35
  */
36
36
  /**
37
37
  * Fetch function that returns a paginated list.
38
- * Receives an optional cursor and returns the next page of results.
38
+ * This function receives an optional cursor. It returns the next page of results.
39
+ *
40
+ * @category Pagination
39
41
  */
40
42
  export type PaginatedFetchFunction<T> = (cursor?: string) => Promise<PaginatedList<T>>;
41
43
  /**
42
44
  * Collects all results from a paginated endpoint by automatically following cursors.
43
45
  *
44
- * This function will keep fetching pages until `has_more` is `false`, collecting all
45
- * results into a single array. Use this when you need all results at once.
46
+ * This function fetches pages until `has_more` is `false`. It collects all results
47
+ * into one array. Use this function when you need all results at once.
46
48
  *
47
49
  * @param fetchPage - Function that fetches a single page of results
48
50
  * @returns Array containing all results from all pages
@@ -82,14 +84,16 @@ export type PaginatedFetchFunction<T> = (cursor?: string) => Promise<PaginatedLi
82
84
  * })
83
85
  * );
84
86
  * ```
87
+ *
88
+ * @category Pagination
85
89
  */
86
90
  export declare function paginate<T>(fetchPage: PaginatedFetchFunction<T>): Promise<T[]>;
87
91
  /**
88
92
  * Creates an async iterator that yields individual items from paginated results.
89
93
  *
90
- * This function provides memory-efficient iteration over large result sets by fetching
91
- * one page at a time and yielding items as needed. Use this with `for await...of` when
92
- * you want to process results one by one without loading everything into memory.
94
+ * This function iterates over large result sets without loading everything into
95
+ * memory. It fetches one page at a time and yields items as needed. Use this function
96
+ * with `for await...of` to process results one at a time.
93
97
  *
94
98
  * @param fetchPage - Function that fetches a single page of results
95
99
  * @yields Individual items from each page
@@ -124,13 +128,15 @@ export declare function paginate<T>(fetchPage: PaginatedFetchFunction<T>): Promi
124
128
  * console.log(result.url);
125
129
  * }
126
130
  * ```
131
+ *
132
+ * @category Pagination
127
133
  */
128
134
  export declare function paginateIterator<T>(fetchPage: PaginatedFetchFunction<T>): AsyncGenerator<T, void, undefined>;
129
135
  /**
130
- * Collects all results and returns both the items and pagination metadata.
136
+ * Collects all results. Returns the items together with pagination metadata.
131
137
  *
132
- * This function is useful when you need to know how many pages were fetched
133
- * or want to track the total number of API calls made.
138
+ * Use this function when you need the page count or the total number of API
139
+ * calls.
134
140
  *
135
141
  * @param fetchPage - Function that fetches a single page of results
136
142
  * @returns Object containing all results and pagination metadata
@@ -143,9 +149,75 @@ export declare function paginateIterator<T>(fetchPage: PaginatedFetchFunction<T>
143
149
  *
144
150
  * console.log(`Fetched ${totalCount} blocks across ${pageCount} pages`);
145
151
  * ```
152
+ *
153
+ * @category Pagination
146
154
  */
147
155
  export declare function paginateWithMetadata<T>(fetchPage: PaginatedFetchFunction<T>): Promise<{
148
156
  items: T[];
149
157
  pageCount: number;
150
158
  totalCount: number;
151
159
  }>;
160
+ /**
161
+ * Fetch function for windowed row collection. It extends
162
+ * {@link PaginatedFetchFunction} with a second parameter: the ISO 8601
163
+ * `created_time` lower bound for the next window. This parameter appears only
164
+ * after the previous window hits the query result limit
165
+ * (`request_status.type === 'incomplete'`). Merge this bound into your own
166
+ * created_time-ascending query, for example
167
+ * `filter.createdTime().onOrAfter(createdTimeCursor)`.
168
+ *
169
+ * @category Pagination
170
+ */
171
+ export type WindowedFetchFunction<T extends {
172
+ id: string;
173
+ createdTime: Date;
174
+ }> = (cursor: string | undefined, createdTimeCursor: string | undefined) => Promise<PaginatedList<T>>;
175
+ /**
176
+ * Iterates over every row of a data source query. It works around the API's
177
+ * 10,000-result-per-query cap.
178
+ *
179
+ * Data source and view queries cap at 10,000 results. When a query hits this cap, the
180
+ * response's `has_more` field is still `false`. Following `next_cursor` and `has_more`
181
+ * alone silently truncates the result set. When a window hits the cap
182
+ * (`request_status.type === 'incomplete'`), this function starts a new query filtered
183
+ * to `created_time >=` the last row seen. It de-duplicates rows by `id` across the
184
+ * window boundary. The query must sort by `created_time` in ascending order.
185
+ *
186
+ * @param fetchWindow - Function that fetches one page. Pass the current cursor. After
187
+ * a window hits the cap, also pass a `created_time` lower bound for the next window.
188
+ * @yields Individual rows across all windows
189
+ *
190
+ * @example
191
+ * ```typescript
192
+ * const rows = collectAllDataSourceRows((cursor, createdTimeCursor) =>
193
+ * notion.dataSources.query(dataSourceId, {
194
+ * start_cursor: cursor,
195
+ * sorts: [{ timestamp: 'created_time', direction: 'ascending' }],
196
+ * filter: createdTimeCursor
197
+ * ? filter.and(baseFilter, filter.createdTime().onOrAfter(createdTimeCursor))
198
+ * : baseFilter,
199
+ * }),
200
+ * );
201
+ * ```
202
+ *
203
+ * @category Pagination
204
+ */
205
+ export declare function iterateAllDataSourceRows<T extends {
206
+ id: string;
207
+ createdTime: Date;
208
+ }>(fetchWindow: WindowedFetchFunction<T>): AsyncGenerator<T, void, undefined>;
209
+ /**
210
+ * Collects every row of a data source query into an array. It works around the API's
211
+ * 10,000-result-per-query cap. See {@link iterateAllDataSourceRows} for the windowing
212
+ * behavior.
213
+ *
214
+ * @param fetchWindow - Function that fetches one page. Pass the current cursor. After
215
+ * a window hits the cap, also pass a `created_time` lower bound for the next window.
216
+ * @returns Array containing all rows across all windows
217
+ *
218
+ * @category Pagination
219
+ */
220
+ export declare function collectAllDataSourceRows<T extends {
221
+ id: string;
222
+ createdTime: Date;
223
+ }>(fetchWindow: WindowedFetchFunction<T>): Promise<T[]>;
@@ -3,11 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.paginate = paginate;
4
4
  exports.paginateIterator = paginateIterator;
5
5
  exports.paginateWithMetadata = paginateWithMetadata;
6
+ exports.iterateAllDataSourceRows = iterateAllDataSourceRows;
7
+ exports.collectAllDataSourceRows = collectAllDataSourceRows;
6
8
  /**
7
9
  * Collects all results from a paginated endpoint by automatically following cursors.
8
10
  *
9
- * This function will keep fetching pages until `has_more` is `false`, collecting all
10
- * results into a single array. Use this when you need all results at once.
11
+ * This function fetches pages until `has_more` is `false`. It collects all results
12
+ * into one array. Use this function when you need all results at once.
11
13
  *
12
14
  * @param fetchPage - Function that fetches a single page of results
13
15
  * @returns Array containing all results from all pages
@@ -47,6 +49,8 @@ exports.paginateWithMetadata = paginateWithMetadata;
47
49
  * })
48
50
  * );
49
51
  * ```
52
+ *
53
+ * @category Pagination
50
54
  */
51
55
  async function paginate(fetchPage) {
52
56
  const all = [];
@@ -61,9 +65,9 @@ async function paginate(fetchPage) {
61
65
  /**
62
66
  * Creates an async iterator that yields individual items from paginated results.
63
67
  *
64
- * This function provides memory-efficient iteration over large result sets by fetching
65
- * one page at a time and yielding items as needed. Use this with `for await...of` when
66
- * you want to process results one by one without loading everything into memory.
68
+ * This function iterates over large result sets without loading everything into
69
+ * memory. It fetches one page at a time and yields items as needed. Use this function
70
+ * with `for await...of` to process results one at a time.
67
71
  *
68
72
  * @param fetchPage - Function that fetches a single page of results
69
73
  * @yields Individual items from each page
@@ -98,6 +102,8 @@ async function paginate(fetchPage) {
98
102
  * console.log(result.url);
99
103
  * }
100
104
  * ```
105
+ *
106
+ * @category Pagination
101
107
  */
102
108
  async function* paginateIterator(fetchPage) {
103
109
  let cursor;
@@ -110,10 +116,10 @@ async function* paginateIterator(fetchPage) {
110
116
  } while (cursor);
111
117
  }
112
118
  /**
113
- * Collects all results and returns both the items and pagination metadata.
119
+ * Collects all results. Returns the items together with pagination metadata.
114
120
  *
115
- * This function is useful when you need to know how many pages were fetched
116
- * or want to track the total number of API calls made.
121
+ * Use this function when you need the page count or the total number of API
122
+ * calls.
117
123
  *
118
124
  * @param fetchPage - Function that fetches a single page of results
119
125
  * @returns Object containing all results and pagination metadata
@@ -126,6 +132,8 @@ async function* paginateIterator(fetchPage) {
126
132
  *
127
133
  * console.log(`Fetched ${totalCount} blocks across ${pageCount} pages`);
128
134
  * ```
135
+ *
136
+ * @category Pagination
129
137
  */
130
138
  async function paginateWithMetadata(fetchPage) {
131
139
  const items = [];
@@ -143,3 +151,101 @@ async function paginateWithMetadata(fetchPage) {
143
151
  totalCount: items.length,
144
152
  };
145
153
  }
154
+ /**
155
+ * Iterates over every row of a data source query. It works around the API's
156
+ * 10,000-result-per-query cap.
157
+ *
158
+ * Data source and view queries cap at 10,000 results. When a query hits this cap, the
159
+ * response's `has_more` field is still `false`. Following `next_cursor` and `has_more`
160
+ * alone silently truncates the result set. When a window hits the cap
161
+ * (`request_status.type === 'incomplete'`), this function starts a new query filtered
162
+ * to `created_time >=` the last row seen. It de-duplicates rows by `id` across the
163
+ * window boundary. The query must sort by `created_time` in ascending order.
164
+ *
165
+ * @param fetchWindow - Function that fetches one page. Pass the current cursor. After
166
+ * a window hits the cap, also pass a `created_time` lower bound for the next window.
167
+ * @yields Individual rows across all windows
168
+ *
169
+ * @example
170
+ * ```typescript
171
+ * const rows = collectAllDataSourceRows((cursor, createdTimeCursor) =>
172
+ * notion.dataSources.query(dataSourceId, {
173
+ * start_cursor: cursor,
174
+ * sorts: [{ timestamp: 'created_time', direction: 'ascending' }],
175
+ * filter: createdTimeCursor
176
+ * ? filter.and(baseFilter, filter.createdTime().onOrAfter(createdTimeCursor))
177
+ * : baseFilter,
178
+ * }),
179
+ * );
180
+ * ```
181
+ *
182
+ * @category Pagination
183
+ */
184
+ async function* iterateAllDataSourceRows(fetchWindow) {
185
+ // Rows repeat across a window boundary only when they share the exact `created_time`
186
+ // used as the next window's lower bound (results are sorted ascending by created_time,
187
+ // so ties are always contiguous). Tracking only that trailing tie group -- instead of
188
+ // every id ever yielded -- keeps memory bounded regardless of result set size.
189
+ let tailTimeMs;
190
+ let tailIds = new Set();
191
+ let cursor;
192
+ let createdTimeCursor;
193
+ let lastCreatedTime;
194
+ let hasMore = true;
195
+ while (hasMore) {
196
+ const response = await fetchWindow(cursor, createdTimeCursor);
197
+ let yieldedThisWindow = false;
198
+ for (const item of response.results) {
199
+ const itemTimeMs = item.createdTime.getTime();
200
+ if (tailTimeMs !== undefined && itemTimeMs === tailTimeMs && tailIds.has(item.id)) {
201
+ continue;
202
+ }
203
+ if (tailTimeMs === undefined || itemTimeMs > tailTimeMs) {
204
+ tailTimeMs = itemTimeMs;
205
+ tailIds = new Set();
206
+ }
207
+ tailIds.add(item.id);
208
+ lastCreatedTime = item.createdTime;
209
+ yieldedThisWindow = true;
210
+ yield item;
211
+ }
212
+ if (response.request_status?.type === 'incomplete' && lastCreatedTime) {
213
+ // has_more is false here, so normal cursor pagination would silently stop short.
214
+ // Start a fresh window scoped to created_time >= the last row seen, de-duping by
215
+ // id across the boundary (created_time, not last_edited_time -- the latter shifts
216
+ // rows between windows).
217
+ if (!yieldedThisWindow) {
218
+ // Every row in this capped window was already seen, meaning more rows share
219
+ // this exact created_time than fit in one window -- the created_time >= filter
220
+ // can't disambiguate further, so re-querying would return the same page forever.
221
+ throw new Error(`More than one window's worth of rows share the same created_time (${lastCreatedTime.toISOString()}); ` +
222
+ 'iterateAllDataSourceRows cannot make forward progress past this timestamp.');
223
+ }
224
+ cursor = undefined;
225
+ createdTimeCursor = lastCreatedTime.toISOString();
226
+ hasMore = true;
227
+ }
228
+ else {
229
+ cursor = response.next_cursor ?? undefined;
230
+ hasMore = cursor !== undefined;
231
+ }
232
+ }
233
+ }
234
+ /**
235
+ * Collects every row of a data source query into an array. It works around the API's
236
+ * 10,000-result-per-query cap. See {@link iterateAllDataSourceRows} for the windowing
237
+ * behavior.
238
+ *
239
+ * @param fetchWindow - Function that fetches one page. Pass the current cursor. After
240
+ * a window hits the cap, also pass a `created_time` lower bound for the next window.
241
+ * @returns Array containing all rows across all windows
242
+ *
243
+ * @category Pagination
244
+ */
245
+ async function collectAllDataSourceRows(fetchWindow) {
246
+ const all = [];
247
+ for await (const item of iterateAllDataSourceRows(fetchWindow)) {
248
+ all.push(item);
249
+ }
250
+ return all;
251
+ }
@@ -22,8 +22,8 @@ declare function database(databaseId: string): {
22
22
  };
23
23
  /**
24
24
  * Create a data source parent object.
25
- * Both data_source_id and database_id are required when creating a page
26
- * with a data source parent.
25
+ * A page with a data source parent needs both `data_source_id` and
26
+ * `database_id`.
27
27
  *
28
28
  * @example
29
29
  * ```ts
@@ -51,7 +51,7 @@ declare function workspace(): {
51
51
  workspace: true;
52
52
  };
53
53
  /**
54
- * Create a block parent object (used for comments on blocks).
54
+ * Create a block parent object for comments on blocks.
55
55
  *
56
56
  * @example
57
57
  * ```ts
@@ -86,6 +86,8 @@ declare function blockParent(blockId: string): {
86
86
  * rich_text: [...],
87
87
  * });
88
88
  * ```
89
+ *
90
+ * @category Helpers
89
91
  */
90
92
  export declare const parent: {
91
93
  page: typeof page;
@@ -28,8 +28,8 @@ function database(databaseId) {
28
28
  }
29
29
  /**
30
30
  * Create a data source parent object.
31
- * Both data_source_id and database_id are required when creating a page
32
- * with a data source parent.
31
+ * A page with a data source parent needs both `data_source_id` and
32
+ * `database_id`.
33
33
  *
34
34
  * @example
35
35
  * ```ts
@@ -56,7 +56,7 @@ function workspace() {
56
56
  return { workspace: true };
57
57
  }
58
58
  /**
59
- * Create a block parent object (used for comments on blocks).
59
+ * Create a block parent object for comments on blocks.
60
60
  *
61
61
  * @example
62
62
  * ```ts
@@ -94,6 +94,8 @@ function blockParent(blockId) {
94
94
  * rich_text: [...],
95
95
  * });
96
96
  * ```
97
+ *
98
+ * @category Helpers
97
99
  */
98
100
  exports.parent = {
99
101
  page,
@@ -181,6 +181,34 @@ declare function people(userIds: string[]): {
181
181
  id: string;
182
182
  }>;
183
183
  };
184
+ /** Options for the verification property's optional date. */
185
+ interface VerificationDateOptions {
186
+ start: string;
187
+ end?: string | null;
188
+ timeZone?: string | null;
189
+ }
190
+ /** The shape of a verification property value. */
191
+ interface VerificationValue {
192
+ verification: {
193
+ state: 'verified' | 'unverified';
194
+ date?: {
195
+ start: string;
196
+ end: string | null;
197
+ time_zone: string | null;
198
+ } | null;
199
+ };
200
+ }
201
+ /**
202
+ * Create a verification property value.
203
+ *
204
+ * @example
205
+ * ```ts
206
+ * prop.verification('verified')
207
+ * prop.verification('verified', { start: '2025-01-15' })
208
+ * prop.verification('unverified')
209
+ * ```
210
+ */
211
+ declare function verification(state: 'verified' | 'unverified', date?: VerificationDateOptions): VerificationValue;
184
212
  /** A single file entry for the files' property. */
185
213
  interface FileEntry {
186
214
  name: string;
@@ -227,6 +255,8 @@ declare function files(entries: FileEntry[]): {
227
255
  * },
228
256
  * });
229
257
  * ```
258
+ *
259
+ * @category Helpers
230
260
  */
231
261
  export declare const prop: {
232
262
  title: typeof title;
@@ -243,5 +273,6 @@ export declare const prop: {
243
273
  relation: typeof relation;
244
274
  people: typeof people;
245
275
  files: typeof files;
276
+ verification: typeof verification;
246
277
  };
247
278
  export {};
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.prop = void 0;
4
4
  const validation_1 = require("../validation");
5
5
  const richText_helpers_1 = require("./richText.helpers");
6
- /** Resolve rich text input to a `NotionRichText` array. */
6
+ /** Resolve rich text input to a `NotionRichText`. */
7
7
  function resolveRichText(input) {
8
8
  if (typeof input === 'string') {
9
9
  (0, validation_1.validateStringLength)(input, validation_1.LIMITS.RICH_TEXT_CONTENT, 'Rich text content');
@@ -210,6 +210,32 @@ function people(userIds) {
210
210
  (0, validation_1.validateArrayLength)(userIds, validation_1.LIMITS.PEOPLE, 'People');
211
211
  return { people: userIds.map((id) => ({ object: 'user', id })) };
212
212
  }
213
+ /**
214
+ * Create a verification property value.
215
+ *
216
+ * @example
217
+ * ```ts
218
+ * prop.verification('verified')
219
+ * prop.verification('verified', { start: '2025-01-15' })
220
+ * prop.verification('unverified')
221
+ * ```
222
+ */
223
+ function verification(state, date) {
224
+ return {
225
+ verification: {
226
+ state,
227
+ ...(date
228
+ ? {
229
+ date: {
230
+ start: date.start,
231
+ end: date.end ?? null,
232
+ time_zone: date.timeZone ?? null,
233
+ },
234
+ }
235
+ : {}),
236
+ },
237
+ };
238
+ }
213
239
  /**
214
240
  * Create a files property value.
215
241
  *
@@ -252,6 +278,8 @@ function files(entries) {
252
278
  * },
253
279
  * });
254
280
  * ```
281
+ *
282
+ * @category Helpers
255
283
  */
256
284
  exports.prop = {
257
285
  title,
@@ -268,4 +296,5 @@ exports.prop = {
268
296
  relation,
269
297
  people,
270
298
  files,
299
+ verification,
271
300
  };
@@ -5,8 +5,9 @@ import type { NotionColor, NotionRichText, NotionUser, TextRichText } from '../s
5
5
  * Do not instantiate directly — use the {@link richText} factory function or
6
6
  * the static helpers on it (`richText.mentionPage`, `richText.equation`, etc.).
7
7
  *
8
- * Call `.build()` to produce a `NotionRichText` array (single-element),
9
- * or pass builders directly to `richText.join()` which calls `.build()` for you.
8
+ * Call `.build()` to produce a single-element `NotionRichText`.
9
+ * Alternatively, pass builders directly to `richText.join()`. This method
10
+ * calls `.build()` for you.
10
11
  *
11
12
  * @example
12
13
  * ```ts
@@ -26,6 +27,8 @@ import type { NotionColor, NotionRichText, NotionUser, TextRichText } from '../s
26
27
  * richText('!'),
27
28
  * );
28
29
  * ```
30
+ *
31
+ * @category Rich Text
29
32
  */
30
33
  export declare class RichTextBuilder {
31
34
  /** @internal */
@@ -52,7 +55,7 @@ export declare class RichTextBuilder {
52
55
  */
53
56
  link(url: string): this;
54
57
  /**
55
- * Build a single-element `NotionRichText` array from this builder.
58
+ * Build a single-element `NotionRichText` from this builder.
56
59
  */
57
60
  build(): NotionRichText;
58
61
  }
@@ -99,8 +102,8 @@ declare function mentionLinkPreview(url: string): RichTextBuilder;
99
102
  */
100
103
  declare function equation(expression: string): RichTextBuilder;
101
104
  /**
102
- * Combine multiple rich text builders (or pre-built `NotionRichText` arrays)
103
- * into a single `NotionRichText` array.
105
+ * Combine multiple rich text builders (or pre-built `NotionRichText` values)
106
+ * into a single `NotionRichText`.
104
107
  *
105
108
  * @example
106
109
  * ```ts
@@ -136,6 +139,8 @@ declare function join(...parts: Array<RichTextBuilder | NotionRichText>): Notion
136
139
  * richText('italic').italic(),
137
140
  * );
138
141
  * ```
142
+ *
143
+ * @category Rich Text
139
144
  */
140
145
  export declare const richText: typeof createRichText & {
141
146
  mentionPage: typeof mentionPage;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.richText = exports.RichTextBuilder = void 0;
4
4
  const validation_1 = require("../validation");
5
5
  /**
6
- * Default annotations object with no formatting applied.
6
+ * Default annotations object with no formatting.
7
7
  */
8
8
  const DEFAULT_ANNOTATIONS = {
9
9
  bold: false,
@@ -19,8 +19,9 @@ const DEFAULT_ANNOTATIONS = {
19
19
  * Do not instantiate directly — use the {@link richText} factory function or
20
20
  * the static helpers on it (`richText.mentionPage`, `richText.equation`, etc.).
21
21
  *
22
- * Call `.build()` to produce a `NotionRichText` array (single-element),
23
- * or pass builders directly to `richText.join()` which calls `.build()` for you.
22
+ * Call `.build()` to produce a single-element `NotionRichText`.
23
+ * Alternatively, pass builders directly to `richText.join()`. This method
24
+ * calls `.build()` for you.
24
25
  *
25
26
  * @example
26
27
  * ```ts
@@ -40,6 +41,8 @@ const DEFAULT_ANNOTATIONS = {
40
41
  * richText('!'),
41
42
  * );
42
43
  * ```
44
+ *
45
+ * @category Rich Text
43
46
  */
44
47
  class RichTextBuilder {
45
48
  /** @internal */
@@ -93,7 +96,7 @@ class RichTextBuilder {
93
96
  return this;
94
97
  }
95
98
  /**
96
- * Build a single-element `NotionRichText` array from this builder.
99
+ * Build a single-element `NotionRichText` from this builder.
97
100
  */
98
101
  build() {
99
102
  return [{ ...this.segment, annotations: { ...this.annotations } }];
@@ -218,8 +221,8 @@ function equation(expression) {
218
221
  return new RichTextBuilder(segment);
219
222
  }
220
223
  /**
221
- * Combine multiple rich text builders (or pre-built `NotionRichText` arrays)
222
- * into a single `NotionRichText` array.
224
+ * Combine multiple rich text builders (or pre-built `NotionRichText` values)
225
+ * into a single `NotionRichText`.
223
226
  *
224
227
  * @example
225
228
  * ```ts
@@ -269,6 +272,8 @@ function join(...parts) {
269
272
  * richText('italic').italic(),
270
273
  * );
271
274
  * ```
275
+ *
276
+ * @category Rich Text
272
277
  */
273
278
  exports.richText = Object.assign(createRichText, {
274
279
  mentionPage,
@@ -34,6 +34,8 @@ declare class TimestampSortBuilder {
34
34
  * ],
35
35
  * });
36
36
  * ```
37
+ *
38
+ * @category Helpers
37
39
  */
38
40
  export declare const sort: {
39
41
  /**
@@ -46,6 +46,8 @@ class TimestampSortBuilder {
46
46
  * ],
47
47
  * });
48
48
  * ```
49
+ *
50
+ * @category Helpers
49
51
  */
50
52
  exports.sort = {
51
53
  /**
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Sign a payload to generate test webhook signatures.
3
+ *
4
+ * @param body - The payload to sign. This function signs a string as-is. It
5
+ * converts anything else with `JSON.stringify` first. This is safe because the
6
+ * caller controls the serialization of their own payload.
7
+ * @param verificationToken - The webhook subscription's verification token
8
+ * @returns The `sha256=<hex digest>` signature
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const signature = webhook.sign({ event: 'page.updated' }, verificationToken);
13
+ * ```
14
+ */
15
+ declare function sign(body: unknown, verificationToken: string): string;
16
+ /**
17
+ * Verify an incoming webhook's `X-Notion-Signature` header via constant-time comparison.
18
+ *
19
+ * IMPORTANT: `rawBody` must be the exact raw request body that Notion sent. Do not use
20
+ * `JSON.stringify(parsedBody)`. Re-serializing a parsed object can produce a different
21
+ * byte sequence (key order, whitespace) than the original signed body, and this
22
+ * silently breaks verification. Use your framework's raw-body access, for example
23
+ * Express's `express.raw()` or `req.rawBody`. Do not use `req.body` after JSON
24
+ * middleware parses it.
25
+ *
26
+ * @param rawBody - The exact raw request body string Notion sent
27
+ * @param signatureHeader - The value of the `X-Notion-Signature` request header
28
+ * @param verificationToken - The webhook subscription's verification token
29
+ * @returns `true` if the signature is valid. Returns `false` for a mismatch or
30
+ * malformed input. This function never throws.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * const isValid = webhook.verifySignature(rawBody, req.headers['x-notion-signature'], verificationToken);
35
+ * ```
36
+ */
37
+ declare function verifySignature(rawBody: string, signatureHeader: string | null | undefined, verificationToken: string): boolean;
38
+ /**
39
+ * Helpers for signing and verifying Notion webhook payloads.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * import { webhook } from '@visus-io/notion-sdk-ts';
44
+ *
45
+ * const isValid = webhook.verifySignature(rawBody, req.headers['x-notion-signature'], verificationToken);
46
+ * ```
47
+ *
48
+ * @category Helpers
49
+ */
50
+ export declare const webhook: {
51
+ sign: typeof sign;
52
+ verifySignature: typeof verifySignature;
53
+ };
54
+ export {};