@visus-io/notion-sdk-ts 3.0.1 → 3.1.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 (95) hide show
  1. package/README.md +7 -6
  2. package/dist/api/asyncTasks.api.d.ts +70 -0
  3. package/dist/api/asyncTasks.api.js +68 -0
  4. package/dist/api/base.api.d.ts +7 -16
  5. package/dist/api/base.api.js +6 -21
  6. package/dist/api/blocks.api.d.ts +433 -73
  7. package/dist/api/blocks.api.js +39 -0
  8. package/dist/api/comments.api.d.ts +40 -5
  9. package/dist/api/comments.api.js +43 -1
  10. package/dist/api/customEmojis.api.d.ts +36 -0
  11. package/dist/api/customEmojis.api.js +36 -0
  12. package/dist/api/dataSources.api.d.ts +70 -12
  13. package/dist/api/dataSources.api.js +29 -5
  14. package/dist/api/databases.api.d.ts +40 -6
  15. package/dist/api/databases.api.js +2 -1
  16. package/dist/api/fileUploads.api.d.ts +7 -1
  17. package/dist/api/fileUploads.api.js +16 -1
  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 +142 -10
  21. package/dist/api/pages.api.js +64 -0
  22. package/dist/api/search.api.d.ts +10 -2
  23. package/dist/api/users.api.d.ts +1 -0
  24. package/dist/api/views.api.d.ts +284 -0
  25. package/dist/api/views.api.js +169 -0
  26. package/dist/client.d.ts +1 -1
  27. package/dist/client.js +10 -4
  28. package/dist/errors.d.ts +5 -1
  29. package/dist/errors.js +6 -0
  30. package/dist/helpers/block.helpers.d.ts +38 -1
  31. package/dist/helpers/block.helpers.js +45 -3
  32. package/dist/helpers/file.helpers.d.ts +36 -1
  33. package/dist/helpers/file.helpers.js +26 -4
  34. package/dist/helpers/filter.helpers.d.ts +6 -6
  35. package/dist/helpers/index.d.ts +3 -2
  36. package/dist/helpers/index.js +5 -1
  37. package/dist/helpers/pagination.helpers.d.ts +56 -0
  38. package/dist/helpers/pagination.helpers.js +86 -0
  39. package/dist/helpers/property.helpers.d.ts +29 -0
  40. package/dist/helpers/property.helpers.js +27 -0
  41. package/dist/helpers/webhook.helpers.d.ts +52 -0
  42. package/dist/helpers/webhook.helpers.js +81 -0
  43. package/dist/models/asyncTask.model.d.ts +59 -0
  44. package/dist/models/asyncTask.model.js +89 -0
  45. package/dist/models/block.model.js +4 -1
  46. package/dist/models/customEmoji.model.d.ts +28 -0
  47. package/dist/models/customEmoji.model.js +42 -0
  48. package/dist/models/dataSource.model.d.ts +3 -3
  49. package/dist/models/dataSource.model.js +1 -1
  50. package/dist/models/database.model.d.ts +7 -3
  51. package/dist/models/database.model.js +7 -1
  52. package/dist/models/index.d.ts +3 -0
  53. package/dist/models/index.js +7 -1
  54. package/dist/models/page.model.d.ts +2 -0
  55. package/dist/models/page.model.js +6 -0
  56. package/dist/models/view.model.d.ts +79 -0
  57. package/dist/models/view.model.js +119 -0
  58. package/dist/notion.d.ts +26 -7
  59. package/dist/notion.js +19 -3
  60. package/dist/schemas/asyncTask.schema.d.ts +42 -0
  61. package/dist/schemas/asyncTask.schema.js +83 -0
  62. package/dist/schemas/block.schema.d.ts +378 -72
  63. package/dist/schemas/block.schema.js +33 -7
  64. package/dist/schemas/comment.schema.d.ts +8 -3
  65. package/dist/schemas/customEmoji.schema.d.ts +13 -0
  66. package/dist/schemas/customEmoji.schema.js +48 -0
  67. package/dist/schemas/dataSource.schema.d.ts +68 -10
  68. package/dist/schemas/dataSource.schema.js +22 -4
  69. package/dist/schemas/database.schema.d.ts +38 -6
  70. package/dist/schemas/database.schema.js +3 -2
  71. package/dist/schemas/fileUpload.schema.d.ts +1 -1
  72. package/dist/schemas/icon.schema.d.ts +92 -0
  73. package/dist/schemas/icon.schema.js +88 -0
  74. package/dist/schemas/index.d.ts +6 -0
  75. package/dist/schemas/index.js +6 -0
  76. package/dist/schemas/meetingNotesQuery.schema.d.ts +4187 -0
  77. package/dist/schemas/meetingNotesQuery.schema.js +62 -0
  78. package/dist/schemas/page.schema.d.ts +46 -9
  79. package/dist/schemas/page.schema.js +4 -2
  80. package/dist/schemas/pageMarkdown.schema.d.ts +59 -0
  81. package/dist/schemas/pageMarkdown.schema.js +65 -0
  82. package/dist/schemas/pageProperties.schema.d.ts +30 -18
  83. package/dist/schemas/pageProperties.schema.js +2 -3
  84. package/dist/schemas/pagination.schema.d.ts +30 -3
  85. package/dist/schemas/pagination.schema.js +18 -1
  86. package/dist/schemas/parent.schema.d.ts +10 -1
  87. package/dist/schemas/parent.schema.js +9 -3
  88. package/dist/schemas/propertyObjects.schema.d.ts +12 -12
  89. package/dist/schemas/richText.schema.d.ts +8 -6
  90. package/dist/schemas/richText.schema.js +1 -1
  91. package/dist/schemas/user.schema.d.ts +2 -0
  92. package/dist/schemas/user.schema.js +2 -1
  93. package/dist/schemas/view.schema.d.ts +1077 -0
  94. package/dist/schemas/view.schema.js +115 -0
  95. package/package.json +4 -3
@@ -16,6 +16,11 @@ interface BlockObject {
16
16
  type: string;
17
17
  [key: string]: unknown;
18
18
  }
19
+ /** Options for paragraph blocks. */
20
+ interface ParagraphOptions extends TextBlockOptions {
21
+ /** Icon shown alongside the paragraph. Only meaningful for paragraphs used as tab items. */
22
+ icon?: unknown;
23
+ }
19
24
  /**
20
25
  * Create a paragraph block.
21
26
  *
@@ -25,7 +30,7 @@ interface BlockObject {
25
30
  * block.paragraph(richText('Hello').bold(), { color: 'blue' })
26
31
  * ```
27
32
  */
28
- declare function paragraph(text: RichTextInput, options?: TextBlockOptions): BlockObject;
33
+ declare function paragraph(text: RichTextInput, options?: ParagraphOptions): BlockObject;
29
34
  /** Options for heading blocks. */
30
35
  interface HeadingOptions {
31
36
  color?: NotionColor;
@@ -35,6 +40,7 @@ interface HeadingOptions {
35
40
  declare function heading1(text: RichTextInput, options?: HeadingOptions): BlockObject;
36
41
  declare function heading2(text: RichTextInput, options?: HeadingOptions): BlockObject;
37
42
  declare function heading3(text: RichTextInput, options?: HeadingOptions): BlockObject;
43
+ declare function heading4(text: RichTextInput, options?: HeadingOptions): BlockObject;
38
44
  declare function bulletedListItem(text: RichTextInput, options?: TextBlockOptions): BlockObject;
39
45
  /** Options for numbered list items. */
40
46
  interface NumberedListOptions extends TextBlockOptions {
@@ -65,6 +71,14 @@ declare function callout(text: RichTextInput, options?: CalloutOptions): BlockOb
65
71
  declare function template(text: RichTextInput, options?: {
66
72
  children?: unknown[];
67
73
  }): BlockObject;
74
+ /**
75
+ * @deprecated Meeting-notes blocks are server-managed -- their real shape (`title`,
76
+ * `status`, and child block IDs for the summary/notes/transcript) is populated by
77
+ * Notion, not hand-constructed by clients. This helper's `rich_text`-based output no
78
+ * longer matches `blockSchema`'s `meeting_notes` shape and is not a valid way to
79
+ * create a meeting-notes block. Kept only to avoid an abrupt removal from the helper
80
+ * surface; do not use for new code.
81
+ */
68
82
  declare function meetingNotes(text: RichTextInput, options?: {
69
83
  children?: unknown[];
70
84
  }): BlockObject;
@@ -115,6 +129,27 @@ declare function table(width: number, options?: TableOptions): BlockObject;
115
129
  declare function tableRow(cells: RichTextInput[]): BlockObject;
116
130
  declare function columnList(columns: unknown[][]): BlockObject;
117
131
  declare function column(children: unknown[]): BlockObject;
132
+ /** A single tab: its label becomes the tab's paragraph rich text, `children` its content. */
133
+ interface TabItem {
134
+ label: RichTextInput;
135
+ icon?: unknown;
136
+ color?: NotionColor;
137
+ children?: unknown[];
138
+ }
139
+ /**
140
+ * Create a tab block. Only `paragraph` blocks may be direct children of a tab block --
141
+ * each tab is modeled as one paragraph, whose rich text is the tab label and whose
142
+ * `children` hold the tab's content.
143
+ *
144
+ * @example
145
+ * ```ts
146
+ * block.tab([
147
+ * { label: 'Overview', children: [block.paragraph('Intro text')] },
148
+ * { label: 'Details', icon: icon.emoji('📋'), children: [block.paragraph('More info')] },
149
+ * ])
150
+ * ```
151
+ */
152
+ declare function tab(tabs: TabItem[]): BlockObject;
118
153
  /**
119
154
  * Create a synced block.
120
155
  *
@@ -160,6 +195,7 @@ export declare const block: {
160
195
  heading1: typeof heading1;
161
196
  heading2: typeof heading2;
162
197
  heading3: typeof heading3;
198
+ heading4: typeof heading4;
163
199
  bulletedListItem: typeof bulletedListItem;
164
200
  numberedListItem: typeof numberedListItem;
165
201
  toDo: typeof toDo;
@@ -185,6 +221,7 @@ export declare const block: {
185
221
  tableRow: typeof tableRow;
186
222
  columnList: typeof columnList;
187
223
  column: typeof column;
224
+ tab: typeof tab;
188
225
  syncedBlock: typeof syncedBlock;
189
226
  };
190
227
  export {};
@@ -29,9 +29,6 @@ function resolveRichText(input) {
29
29
  }
30
30
  return input;
31
31
  }
32
- // ---------------------------------------------------------------------------
33
- // Text blocks
34
- // ---------------------------------------------------------------------------
35
32
  /**
36
33
  * Create a paragraph block.
37
34
  *
@@ -48,6 +45,7 @@ function paragraph(text, options) {
48
45
  paragraph: {
49
46
  rich_text: resolveRichText(text),
50
47
  color: options?.color ?? 'default',
48
+ ...(options?.icon ? { icon: options.icon } : {}),
51
49
  ...(options?.children ? { children: options.children } : {}),
52
50
  },
53
51
  };
@@ -88,6 +86,18 @@ function heading3(text, options) {
88
86
  },
89
87
  };
90
88
  }
89
+ function heading4(text, options) {
90
+ return {
91
+ object: 'block',
92
+ type: 'heading_4',
93
+ heading_4: {
94
+ rich_text: resolveRichText(text),
95
+ color: options?.color ?? 'default',
96
+ is_toggleable: options?.isToggleable ?? false,
97
+ ...(options?.children ? { children: options.children } : {}),
98
+ },
99
+ };
100
+ }
91
101
  function bulletedListItem(text, options) {
92
102
  return {
93
103
  object: 'block',
@@ -170,6 +180,14 @@ function template(text, options) {
170
180
  },
171
181
  };
172
182
  }
183
+ /**
184
+ * @deprecated Meeting-notes blocks are server-managed -- their real shape (`title`,
185
+ * `status`, and child block IDs for the summary/notes/transcript) is populated by
186
+ * Notion, not hand-constructed by clients. This helper's `rich_text`-based output no
187
+ * longer matches `blockSchema`'s `meeting_notes` shape and is not a valid way to
188
+ * create a meeting-notes block. Kept only to avoid an abrupt removal from the helper
189
+ * surface; do not use for new code.
190
+ */
173
191
  function meetingNotes(text, options) {
174
192
  return {
175
193
  object: 'block',
@@ -348,6 +366,28 @@ function column(children) {
348
366
  column: { children },
349
367
  };
350
368
  }
369
+ /**
370
+ * Create a tab block. Only `paragraph` blocks may be direct children of a tab block --
371
+ * each tab is modeled as one paragraph, whose rich text is the tab label and whose
372
+ * `children` hold the tab's content.
373
+ *
374
+ * @example
375
+ * ```ts
376
+ * block.tab([
377
+ * { label: 'Overview', children: [block.paragraph('Intro text')] },
378
+ * { label: 'Details', icon: icon.emoji('📋'), children: [block.paragraph('More info')] },
379
+ * ])
380
+ * ```
381
+ */
382
+ function tab(tabs) {
383
+ return {
384
+ object: 'block',
385
+ type: 'tab',
386
+ tab: {
387
+ children: tabs.map((item) => paragraph(item.label, { color: item.color, icon: item.icon, children: item.children })),
388
+ },
389
+ };
390
+ }
351
391
  // ---------------------------------------------------------------------------
352
392
  // Synced blocks
353
393
  // ---------------------------------------------------------------------------
@@ -406,6 +446,7 @@ exports.block = {
406
446
  heading1,
407
447
  heading2,
408
448
  heading3,
449
+ heading4,
409
450
  bulletedListItem,
410
451
  numberedListItem,
411
452
  toDo,
@@ -435,6 +476,7 @@ exports.block = {
435
476
  tableRow,
436
477
  columnList,
437
478
  column,
479
+ tab,
438
480
  // Synced
439
481
  syncedBlock,
440
482
  };
@@ -1,3 +1,4 @@
1
+ import type { NativeIconColor } from '../schemas/icon.schema';
1
2
  interface EmojiIcon {
2
3
  type: 'emoji';
3
4
  emoji: string;
@@ -14,6 +15,19 @@ interface FileUploadRef {
14
15
  id: string;
15
16
  };
16
17
  }
18
+ interface NativeIconRef {
19
+ type: 'icon';
20
+ icon: {
21
+ name: string;
22
+ color?: NativeIconColor;
23
+ };
24
+ }
25
+ interface CustomEmojiIconRef {
26
+ type: 'custom_emoji';
27
+ custom_emoji: {
28
+ id: string;
29
+ };
30
+ }
17
31
  /**
18
32
  * Create an emoji icon object.
19
33
  *
@@ -42,7 +56,26 @@ declare function externalIcon(url: string): ExternalRef;
42
56
  */
43
57
  declare function fileUploadIcon(id: string): FileUploadRef;
44
58
  /**
45
- * Helpers for constructing icon objects (emoji, external URL, or file upload).
59
+ * Create a native (icon-picker) icon object.
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * icon.native('star circle', 'blue')
64
+ * ```
65
+ */
66
+ declare function nativeIcon(name: string, color?: NativeIconColor): NativeIconRef;
67
+ /**
68
+ * Create a custom emoji icon object, referencing a workspace custom emoji by id.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * icon.customEmoji('emoji-id')
73
+ * ```
74
+ */
75
+ declare function customEmojiIcon(id: string): CustomEmojiIconRef;
76
+ /**
77
+ * Helpers for constructing icon objects (emoji, external URL, file upload,
78
+ * native icon, or custom emoji).
46
79
  *
47
80
  * @example
48
81
  * ```ts
@@ -59,6 +92,8 @@ export declare const icon: {
59
92
  emoji: typeof emojiIcon;
60
93
  external: typeof externalIcon;
61
94
  fileUpload: typeof fileUploadIcon;
95
+ native: typeof nativeIcon;
96
+ customEmoji: typeof customEmojiIcon;
62
97
  };
63
98
  /**
64
99
  * Create an external cover image object.
@@ -1,7 +1,4 @@
1
1
  "use strict";
2
- // ---------------------------------------------------------------------------
3
- // Return types
4
- // ---------------------------------------------------------------------------
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.notionFile = exports.cover = exports.icon = void 0;
7
4
  // ---------------------------------------------------------------------------
@@ -41,7 +38,30 @@ function fileUploadIcon(id) {
41
38
  return { type: 'file_upload', file_upload: { id } };
42
39
  }
43
40
  /**
44
- * Helpers for constructing icon objects (emoji, external URL, or file upload).
41
+ * Create a native (icon-picker) icon object.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * icon.native('star circle', 'blue')
46
+ * ```
47
+ */
48
+ function nativeIcon(name, color) {
49
+ return { type: 'icon', icon: { name, ...(color ? { color } : {}) } };
50
+ }
51
+ /**
52
+ * Create a custom emoji icon object, referencing a workspace custom emoji by id.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * icon.customEmoji('emoji-id')
57
+ * ```
58
+ */
59
+ function customEmojiIcon(id) {
60
+ return { type: 'custom_emoji', custom_emoji: { id } };
61
+ }
62
+ /**
63
+ * Helpers for constructing icon objects (emoji, external URL, file upload,
64
+ * native icon, or custom emoji).
45
65
  *
46
66
  * @example
47
67
  * ```ts
@@ -58,6 +78,8 @@ exports.icon = {
58
78
  emoji: emojiIcon,
59
79
  external: externalIcon,
60
80
  fileUpload: fileUploadIcon,
81
+ native: nativeIcon,
82
+ customEmoji: customEmojiIcon,
61
83
  };
62
84
  // ---------------------------------------------------------------------------
63
85
  // Cover helpers
@@ -38,8 +38,8 @@ declare class CheckboxFilter {
38
38
  declare class SelectFilter {
39
39
  private readonly property;
40
40
  constructor(property: string);
41
- equals(value: string): FilterCondition;
42
- doesNotEqual(value: string): FilterCondition;
41
+ equals(value: string | string[]): FilterCondition;
42
+ doesNotEqual(value: string | string[]): FilterCondition;
43
43
  isEmpty(): FilterCondition;
44
44
  isNotEmpty(): FilterCondition;
45
45
  }
@@ -47,8 +47,8 @@ declare class SelectFilter {
47
47
  declare class MultiSelectFilter {
48
48
  private readonly property;
49
49
  constructor(property: string);
50
- contains(value: string): FilterCondition;
51
- doesNotContain(value: string): FilterCondition;
50
+ contains(value: string | string[]): FilterCondition;
51
+ doesNotContain(value: string | string[]): FilterCondition;
52
52
  isEmpty(): FilterCondition;
53
53
  isNotEmpty(): FilterCondition;
54
54
  }
@@ -56,8 +56,8 @@ declare class MultiSelectFilter {
56
56
  declare class StatusFilter {
57
57
  private readonly property;
58
58
  constructor(property: string);
59
- equals(value: string): FilterCondition;
60
- doesNotEqual(value: string): FilterCondition;
59
+ equals(value: string | string[]): FilterCondition;
60
+ doesNotEqual(value: string | string[]): FilterCondition;
61
61
  isEmpty(): FilterCondition;
62
62
  isNotEmpty(): FilterCondition;
63
63
  }
@@ -2,9 +2,10 @@ export { block } from './block.helpers';
2
2
  export type { RichTextInput } from './block.helpers';
3
3
  export { cover, icon, notionFile } from './file.helpers';
4
4
  export { filter } from './filter.helpers';
5
- export { paginate, paginateIterator, paginateWithMetadata } from './pagination.helpers';
6
- export type { PaginatedFetchFunction } from './pagination.helpers';
5
+ export { collectAllDataSourceRows, iterateAllDataSourceRows, paginate, paginateIterator, paginateWithMetadata, } from './pagination.helpers';
6
+ export type { PaginatedFetchFunction, WindowedFetchFunction } from './pagination.helpers';
7
7
  export { parent } from './parent.helpers';
8
8
  export { prop } from './property.helpers';
9
9
  export { RichTextBuilder, richText } from './richText.helpers';
10
10
  export { sort } from './sort.helpers';
11
+ export { webhook } from './webhook.helpers';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sort = exports.richText = exports.RichTextBuilder = exports.prop = exports.parent = exports.paginateWithMetadata = exports.paginateIterator = exports.paginate = exports.filter = exports.notionFile = exports.icon = exports.cover = exports.block = void 0;
3
+ exports.webhook = exports.sort = exports.richText = exports.RichTextBuilder = exports.prop = exports.parent = exports.paginateWithMetadata = exports.paginateIterator = exports.paginate = exports.iterateAllDataSourceRows = exports.collectAllDataSourceRows = exports.filter = exports.notionFile = exports.icon = exports.cover = exports.block = void 0;
4
4
  var block_helpers_1 = require("./block.helpers");
5
5
  Object.defineProperty(exports, "block", { enumerable: true, get: function () { return block_helpers_1.block; } });
6
6
  var file_helpers_1 = require("./file.helpers");
@@ -10,6 +10,8 @@ Object.defineProperty(exports, "notionFile", { enumerable: true, get: function (
10
10
  var filter_helpers_1 = require("./filter.helpers");
11
11
  Object.defineProperty(exports, "filter", { enumerable: true, get: function () { return filter_helpers_1.filter; } });
12
12
  var pagination_helpers_1 = require("./pagination.helpers");
13
+ Object.defineProperty(exports, "collectAllDataSourceRows", { enumerable: true, get: function () { return pagination_helpers_1.collectAllDataSourceRows; } });
14
+ Object.defineProperty(exports, "iterateAllDataSourceRows", { enumerable: true, get: function () { return pagination_helpers_1.iterateAllDataSourceRows; } });
13
15
  Object.defineProperty(exports, "paginate", { enumerable: true, get: function () { return pagination_helpers_1.paginate; } });
14
16
  Object.defineProperty(exports, "paginateIterator", { enumerable: true, get: function () { return pagination_helpers_1.paginateIterator; } });
15
17
  Object.defineProperty(exports, "paginateWithMetadata", { enumerable: true, get: function () { return pagination_helpers_1.paginateWithMetadata; } });
@@ -22,3 +24,5 @@ Object.defineProperty(exports, "RichTextBuilder", { enumerable: true, get: funct
22
24
  Object.defineProperty(exports, "richText", { enumerable: true, get: function () { return richText_helpers_1.richText; } });
23
25
  var sort_helpers_1 = require("./sort.helpers");
24
26
  Object.defineProperty(exports, "sort", { enumerable: true, get: function () { return sort_helpers_1.sort; } });
27
+ var webhook_helpers_1 = require("./webhook.helpers");
28
+ Object.defineProperty(exports, "webhook", { enumerable: true, get: function () { return webhook_helpers_1.webhook; } });
@@ -149,3 +149,59 @@ export declare function paginateWithMetadata<T>(fetchPage: PaginatedFetchFunctio
149
149
  pageCount: number;
150
150
  totalCount: number;
151
151
  }>;
152
+ /**
153
+ * Fetch function for windowed row collection. Same as {@link PaginatedFetchFunction} plus
154
+ * a second parameter carrying the ISO 8601 `created_time` lower bound for the *next*
155
+ * window, present once the previous window was capped at the query result limit
156
+ * (`request_status.type === 'incomplete'`). The caller merges this into their own
157
+ * created_time-ascending query, e.g. `filter.createdTime('Created time').onOrAfter(createdTimeCursor)`.
158
+ */
159
+ export type WindowedFetchFunction<T extends {
160
+ id: string;
161
+ createdTime: Date;
162
+ }> = (cursor: string | undefined, createdTimeCursor: string | undefined) => Promise<PaginatedList<T>>;
163
+ /**
164
+ * Iterates over every row of a data source query, transparently working around the
165
+ * API's 10,000-result-per-query cap.
166
+ *
167
+ * Data source (and view) queries cap at 10,000 results; when capped, the response's
168
+ * `has_more` is still `false`, so following `next_cursor`/`has_more` alone silently
169
+ * truncates the result set. When a window is capped (`request_status.type ===
170
+ * 'incomplete'`), this starts a new query filtered to `created_time >=` the last row
171
+ * seen, de-duplicating by `id` across the window boundary. Requires the query to be
172
+ * sorted by `created_time` ascending.
173
+ *
174
+ * @param fetchWindow - Function that fetches one page, given the current cursor and
175
+ * (once a window has been capped) a `created_time` lower bound for the next window
176
+ * @yields Individual rows across all windows
177
+ *
178
+ * @example
179
+ * ```typescript
180
+ * const rows = collectAllDataSourceRows((cursor, createdTimeCursor) =>
181
+ * notion.dataSources.query(dataSourceId, {
182
+ * start_cursor: cursor,
183
+ * sorts: [{ timestamp: 'created_time', direction: 'ascending' }],
184
+ * filter: createdTimeCursor
185
+ * ? filter.and(baseFilter, filter.createdTime('Created time').onOrAfter(createdTimeCursor))
186
+ * : baseFilter,
187
+ * }),
188
+ * );
189
+ * ```
190
+ */
191
+ export declare function iterateAllDataSourceRows<T extends {
192
+ id: string;
193
+ createdTime: Date;
194
+ }>(fetchWindow: WindowedFetchFunction<T>): AsyncGenerator<T, void, undefined>;
195
+ /**
196
+ * Collects every row of a data source query into an array, transparently working
197
+ * around the API's 10,000-result-per-query cap. See {@link iterateAllDataSourceRows}
198
+ * for the windowing behavior.
199
+ *
200
+ * @param fetchWindow - Function that fetches one page, given the current cursor and
201
+ * (once a window has been capped) a `created_time` lower bound for the next window
202
+ * @returns Array containing all rows across all windows
203
+ */
204
+ export declare function collectAllDataSourceRows<T extends {
205
+ id: string;
206
+ createdTime: Date;
207
+ }>(fetchWindow: WindowedFetchFunction<T>): Promise<T[]>;
@@ -3,6 +3,8 @@ 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
  *
@@ -143,3 +145,87 @@ async function paginateWithMetadata(fetchPage) {
143
145
  totalCount: items.length,
144
146
  };
145
147
  }
148
+ /**
149
+ * Iterates over every row of a data source query, transparently working around the
150
+ * API's 10,000-result-per-query cap.
151
+ *
152
+ * Data source (and view) queries cap at 10,000 results; when capped, the response's
153
+ * `has_more` is still `false`, so following `next_cursor`/`has_more` alone silently
154
+ * truncates the result set. When a window is capped (`request_status.type ===
155
+ * 'incomplete'`), this starts a new query filtered to `created_time >=` the last row
156
+ * seen, de-duplicating by `id` across the window boundary. Requires the query to be
157
+ * sorted by `created_time` ascending.
158
+ *
159
+ * @param fetchWindow - Function that fetches one page, given the current cursor and
160
+ * (once a window has been capped) a `created_time` lower bound for the next window
161
+ * @yields Individual rows across all windows
162
+ *
163
+ * @example
164
+ * ```typescript
165
+ * const rows = collectAllDataSourceRows((cursor, createdTimeCursor) =>
166
+ * notion.dataSources.query(dataSourceId, {
167
+ * start_cursor: cursor,
168
+ * sorts: [{ timestamp: 'created_time', direction: 'ascending' }],
169
+ * filter: createdTimeCursor
170
+ * ? filter.and(baseFilter, filter.createdTime('Created time').onOrAfter(createdTimeCursor))
171
+ * : baseFilter,
172
+ * }),
173
+ * );
174
+ * ```
175
+ */
176
+ async function* iterateAllDataSourceRows(fetchWindow) {
177
+ const seenIds = new Set();
178
+ let cursor;
179
+ let createdTimeCursor;
180
+ let lastCreatedTime;
181
+ let hasMore = true;
182
+ while (hasMore) {
183
+ const response = await fetchWindow(cursor, createdTimeCursor);
184
+ let yieldedThisWindow = false;
185
+ for (const item of response.results) {
186
+ if (seenIds.has(item.id)) {
187
+ continue;
188
+ }
189
+ seenIds.add(item.id);
190
+ lastCreatedTime = item.createdTime;
191
+ yieldedThisWindow = true;
192
+ yield item;
193
+ }
194
+ if (response.request_status?.type === 'incomplete' && lastCreatedTime) {
195
+ // has_more is false here, so normal cursor pagination would silently stop short.
196
+ // Start a fresh window scoped to created_time >= the last row seen, de-duping by
197
+ // id across the boundary (created_time, not last_edited_time -- the latter shifts
198
+ // rows between windows).
199
+ if (!yieldedThisWindow) {
200
+ // Every row in this capped window was already seen, meaning more rows share
201
+ // this exact created_time than fit in one window -- the created_time >= filter
202
+ // can't disambiguate further, so re-querying would return the same page forever.
203
+ throw new Error(`More than one window's worth of rows share the same created_time (${lastCreatedTime.toISOString()}); ` +
204
+ 'iterateAllDataSourceRows cannot make forward progress past this timestamp.');
205
+ }
206
+ cursor = undefined;
207
+ createdTimeCursor = lastCreatedTime.toISOString();
208
+ hasMore = true;
209
+ }
210
+ else {
211
+ cursor = response.next_cursor ?? undefined;
212
+ hasMore = cursor !== undefined;
213
+ }
214
+ }
215
+ }
216
+ /**
217
+ * Collects every row of a data source query into an array, transparently working
218
+ * around the API's 10,000-result-per-query cap. See {@link iterateAllDataSourceRows}
219
+ * for the windowing behavior.
220
+ *
221
+ * @param fetchWindow - Function that fetches one page, given the current cursor and
222
+ * (once a window has been capped) a `created_time` lower bound for the next window
223
+ * @returns Array containing all rows across all windows
224
+ */
225
+ async function collectAllDataSourceRows(fetchWindow) {
226
+ const all = [];
227
+ for await (const item of iterateAllDataSourceRows(fetchWindow)) {
228
+ all.push(item);
229
+ }
230
+ return all;
231
+ }
@@ -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;
@@ -243,5 +271,6 @@ export declare const prop: {
243
271
  relation: typeof relation;
244
272
  people: typeof people;
245
273
  files: typeof files;
274
+ verification: typeof verification;
246
275
  };
247
276
  export {};
@@ -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
  *
@@ -268,4 +294,5 @@ exports.prop = {
268
294
  relation,
269
295
  people,
270
296
  files,
297
+ verification,
271
298
  };
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Sign a payload, for generating test webhook signatures.
3
+ *
4
+ * @param body - The payload to sign. A string is signed as-is; anything else is
5
+ * `JSON.stringify`'d first -- safe here because the caller controls the exact
6
+ * serialization of a payload they're constructing themselves.
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 Notion sent, not
20
+ * `JSON.stringify(parsedBody)` -- re-serializing a parsed object can produce a
21
+ * different byte sequence (key order, whitespace) than what was actually signed,
22
+ * silently breaking verification. Use your framework's raw-body access (e.g.
23
+ * Express's `express.raw()` / `req.rawBody`), not `req.body` after JSON middleware
24
+ * has already parsed 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; `false` for any mismatch or malformed
30
+ * input (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
+ export declare const webhook: {
49
+ sign: typeof sign;
50
+ verifySignature: typeof verifySignature;
51
+ };
52
+ export {};