@visus-io/notion-sdk-ts 1.0.0 → 2.0.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 (204) hide show
  1. package/README.md +56 -786
  2. package/dist/api/base.api.d.ts +161 -0
  3. package/dist/api/base.api.js +228 -0
  4. package/dist/api/blocks.api.d.ts +3687 -4
  5. package/dist/api/blocks.api.js +16 -47
  6. package/dist/api/comments.api.d.ts +259 -4
  7. package/dist/api/comments.api.js +11 -29
  8. package/dist/api/dataSources.api.d.ts +788 -4
  9. package/dist/api/dataSources.api.js +14 -28
  10. package/dist/api/databases.api.d.ts +513 -14
  11. package/dist/api/databases.api.js +25 -50
  12. package/dist/api/fileUploads.api.d.ts +25 -3
  13. package/dist/api/fileUploads.api.js +7 -2
  14. package/dist/api/index.d.ts +0 -1
  15. package/dist/api/index.js +0 -1
  16. package/dist/api/pages.api.d.ts +864 -3
  17. package/dist/api/pages.api.js +14 -28
  18. package/dist/api/search.api.d.ts +9 -7
  19. package/dist/api/search.api.js +12 -17
  20. package/dist/api/users.api.d.ts +40 -4
  21. package/dist/api/users.api.js +12 -35
  22. package/dist/client.d.ts +1 -2
  23. package/dist/client.js +1 -2
  24. package/dist/errors.d.ts +0 -1
  25. package/dist/errors.js +0 -1
  26. package/dist/helpers/block.helpers.d.ts +0 -1
  27. package/dist/helpers/block.helpers.js +0 -1
  28. package/dist/helpers/file.helpers.d.ts +0 -1
  29. package/dist/helpers/file.helpers.js +0 -1
  30. package/dist/helpers/filter.helpers.d.ts +0 -1
  31. package/dist/helpers/filter.helpers.js +0 -1
  32. package/dist/helpers/index.d.ts +0 -1
  33. package/dist/helpers/index.js +0 -1
  34. package/dist/helpers/pagination.helpers.d.ts +0 -1
  35. package/dist/helpers/pagination.helpers.js +0 -1
  36. package/dist/helpers/parent.helpers.d.ts +10 -3
  37. package/dist/helpers/parent.helpers.js +10 -4
  38. package/dist/helpers/property.helpers.d.ts +0 -1
  39. package/dist/helpers/property.helpers.js +0 -1
  40. package/dist/helpers/richText.helpers.d.ts +0 -1
  41. package/dist/helpers/richText.helpers.js +0 -1
  42. package/dist/helpers/sort.helpers.d.ts +0 -1
  43. package/dist/helpers/sort.helpers.js +0 -1
  44. package/dist/index.d.ts +0 -1
  45. package/dist/index.js +0 -1
  46. package/dist/models/base.model.d.ts +0 -1
  47. package/dist/models/base.model.js +0 -1
  48. package/dist/models/block.model.d.ts +0 -1
  49. package/dist/models/block.model.js +0 -1
  50. package/dist/models/comment.model.d.ts +0 -1
  51. package/dist/models/comment.model.js +0 -1
  52. package/dist/models/dataSource.model.d.ts +0 -1
  53. package/dist/models/dataSource.model.js +0 -1
  54. package/dist/models/database.model.d.ts +0 -1
  55. package/dist/models/database.model.js +0 -1
  56. package/dist/models/fileUpload.model.d.ts +0 -1
  57. package/dist/models/fileUpload.model.js +0 -1
  58. package/dist/models/index.d.ts +0 -1
  59. package/dist/models/index.js +0 -1
  60. package/dist/models/page.model.d.ts +0 -1
  61. package/dist/models/page.model.js +0 -1
  62. package/dist/models/richText.model.d.ts +0 -1
  63. package/dist/models/richText.model.js +0 -1
  64. package/dist/models/user.model.d.ts +0 -1
  65. package/dist/models/user.model.js +0 -1
  66. package/dist/notion.d.ts +0 -1
  67. package/dist/notion.js +0 -1
  68. package/dist/schemas/block.schema.d.ts +0 -1
  69. package/dist/schemas/block.schema.js +0 -1
  70. package/dist/schemas/codeLanguages.d.ts +0 -1
  71. package/dist/schemas/codeLanguages.js +0 -1
  72. package/dist/schemas/colors.d.ts +0 -1
  73. package/dist/schemas/colors.js +0 -1
  74. package/dist/schemas/comment.schema.d.ts +0 -1
  75. package/dist/schemas/comment.schema.js +0 -1
  76. package/dist/schemas/dataSource.schema.d.ts +0 -1
  77. package/dist/schemas/dataSource.schema.js +0 -1
  78. package/dist/schemas/database.schema.d.ts +0 -1
  79. package/dist/schemas/database.schema.js +0 -1
  80. package/dist/schemas/emoji.schema.d.ts +0 -1
  81. package/dist/schemas/emoji.schema.js +0 -1
  82. package/dist/schemas/file.schema.d.ts +0 -1
  83. package/dist/schemas/file.schema.js +0 -1
  84. package/dist/schemas/fileUpload.schema.d.ts +0 -1
  85. package/dist/schemas/fileUpload.schema.js +0 -1
  86. package/dist/schemas/index.d.ts +0 -1
  87. package/dist/schemas/index.js +0 -1
  88. package/dist/schemas/page.schema.d.ts +0 -1
  89. package/dist/schemas/page.schema.js +0 -1
  90. package/dist/schemas/pageProperties.schema.d.ts +0 -1
  91. package/dist/schemas/pageProperties.schema.js +0 -1
  92. package/dist/schemas/pagination.schema.d.ts +5 -2
  93. package/dist/schemas/pagination.schema.js +2 -1
  94. package/dist/schemas/parent.schema.d.ts +0 -1
  95. package/dist/schemas/parent.schema.js +0 -1
  96. package/dist/schemas/propertyObjects.schema.d.ts +0 -1
  97. package/dist/schemas/propertyObjects.schema.js +0 -1
  98. package/dist/schemas/richText.schema.d.ts +0 -1
  99. package/dist/schemas/richText.schema.js +0 -1
  100. package/dist/schemas/user.schema.d.ts +0 -1
  101. package/dist/schemas/user.schema.js +0 -1
  102. package/dist/validation.d.ts +0 -1
  103. package/dist/validation.js +0 -1
  104. package/package.json +1 -1
  105. package/dist/api/blocks.api.d.ts.map +0 -1
  106. package/dist/api/blocks.api.js.map +0 -1
  107. package/dist/api/comments.api.d.ts.map +0 -1
  108. package/dist/api/comments.api.js.map +0 -1
  109. package/dist/api/dataSources.api.d.ts.map +0 -1
  110. package/dist/api/dataSources.api.js.map +0 -1
  111. package/dist/api/databases.api.d.ts.map +0 -1
  112. package/dist/api/databases.api.js.map +0 -1
  113. package/dist/api/fileUploads.api.d.ts.map +0 -1
  114. package/dist/api/fileUploads.api.js.map +0 -1
  115. package/dist/api/index.d.ts.map +0 -1
  116. package/dist/api/index.js.map +0 -1
  117. package/dist/api/pages.api.d.ts.map +0 -1
  118. package/dist/api/pages.api.js.map +0 -1
  119. package/dist/api/search.api.d.ts.map +0 -1
  120. package/dist/api/search.api.js.map +0 -1
  121. package/dist/api/users.api.d.ts.map +0 -1
  122. package/dist/api/users.api.js.map +0 -1
  123. package/dist/client.d.ts.map +0 -1
  124. package/dist/client.js.map +0 -1
  125. package/dist/errors.d.ts.map +0 -1
  126. package/dist/errors.js.map +0 -1
  127. package/dist/helpers/block.helpers.d.ts.map +0 -1
  128. package/dist/helpers/block.helpers.js.map +0 -1
  129. package/dist/helpers/file.helpers.d.ts.map +0 -1
  130. package/dist/helpers/file.helpers.js.map +0 -1
  131. package/dist/helpers/filter.helpers.d.ts.map +0 -1
  132. package/dist/helpers/filter.helpers.js.map +0 -1
  133. package/dist/helpers/index.d.ts.map +0 -1
  134. package/dist/helpers/index.js.map +0 -1
  135. package/dist/helpers/pagination.helpers.d.ts.map +0 -1
  136. package/dist/helpers/pagination.helpers.js.map +0 -1
  137. package/dist/helpers/parent.helpers.d.ts.map +0 -1
  138. package/dist/helpers/parent.helpers.js.map +0 -1
  139. package/dist/helpers/property.helpers.d.ts.map +0 -1
  140. package/dist/helpers/property.helpers.js.map +0 -1
  141. package/dist/helpers/richText.helpers.d.ts.map +0 -1
  142. package/dist/helpers/richText.helpers.js.map +0 -1
  143. package/dist/helpers/sort.helpers.d.ts.map +0 -1
  144. package/dist/helpers/sort.helpers.js.map +0 -1
  145. package/dist/index.d.ts.map +0 -1
  146. package/dist/index.js.map +0 -1
  147. package/dist/models/base.model.d.ts.map +0 -1
  148. package/dist/models/base.model.js.map +0 -1
  149. package/dist/models/block.model.d.ts.map +0 -1
  150. package/dist/models/block.model.js.map +0 -1
  151. package/dist/models/comment.model.d.ts.map +0 -1
  152. package/dist/models/comment.model.js.map +0 -1
  153. package/dist/models/dataSource.model.d.ts.map +0 -1
  154. package/dist/models/dataSource.model.js.map +0 -1
  155. package/dist/models/database.model.d.ts.map +0 -1
  156. package/dist/models/database.model.js.map +0 -1
  157. package/dist/models/fileUpload.model.d.ts.map +0 -1
  158. package/dist/models/fileUpload.model.js.map +0 -1
  159. package/dist/models/index.d.ts.map +0 -1
  160. package/dist/models/index.js.map +0 -1
  161. package/dist/models/page.model.d.ts.map +0 -1
  162. package/dist/models/page.model.js.map +0 -1
  163. package/dist/models/richText.model.d.ts.map +0 -1
  164. package/dist/models/richText.model.js.map +0 -1
  165. package/dist/models/user.model.d.ts.map +0 -1
  166. package/dist/models/user.model.js.map +0 -1
  167. package/dist/notion.d.ts.map +0 -1
  168. package/dist/notion.js.map +0 -1
  169. package/dist/schemas/block.schema.d.ts.map +0 -1
  170. package/dist/schemas/block.schema.js.map +0 -1
  171. package/dist/schemas/codeLanguages.d.ts.map +0 -1
  172. package/dist/schemas/codeLanguages.js.map +0 -1
  173. package/dist/schemas/colors.d.ts.map +0 -1
  174. package/dist/schemas/colors.js.map +0 -1
  175. package/dist/schemas/comment.schema.d.ts.map +0 -1
  176. package/dist/schemas/comment.schema.js.map +0 -1
  177. package/dist/schemas/dataSource.schema.d.ts.map +0 -1
  178. package/dist/schemas/dataSource.schema.js.map +0 -1
  179. package/dist/schemas/database.schema.d.ts.map +0 -1
  180. package/dist/schemas/database.schema.js.map +0 -1
  181. package/dist/schemas/emoji.schema.d.ts.map +0 -1
  182. package/dist/schemas/emoji.schema.js.map +0 -1
  183. package/dist/schemas/file.schema.d.ts.map +0 -1
  184. package/dist/schemas/file.schema.js.map +0 -1
  185. package/dist/schemas/fileUpload.schema.d.ts.map +0 -1
  186. package/dist/schemas/fileUpload.schema.js.map +0 -1
  187. package/dist/schemas/index.d.ts.map +0 -1
  188. package/dist/schemas/index.js.map +0 -1
  189. package/dist/schemas/page.schema.d.ts.map +0 -1
  190. package/dist/schemas/page.schema.js.map +0 -1
  191. package/dist/schemas/pageProperties.schema.d.ts.map +0 -1
  192. package/dist/schemas/pageProperties.schema.js.map +0 -1
  193. package/dist/schemas/pagination.schema.d.ts.map +0 -1
  194. package/dist/schemas/pagination.schema.js.map +0 -1
  195. package/dist/schemas/parent.schema.d.ts.map +0 -1
  196. package/dist/schemas/parent.schema.js.map +0 -1
  197. package/dist/schemas/propertyObjects.schema.d.ts.map +0 -1
  198. package/dist/schemas/propertyObjects.schema.js.map +0 -1
  199. package/dist/schemas/richText.schema.d.ts.map +0 -1
  200. package/dist/schemas/richText.schema.js.map +0 -1
  201. package/dist/schemas/user.schema.d.ts.map +0 -1
  202. package/dist/schemas/user.schema.js.map +0 -1
  203. package/dist/validation.d.ts.map +0 -1
  204. package/dist/validation.js.map +0 -1
package/README.md CHANGED
@@ -5,42 +5,12 @@
5
5
  [![Sonar Quality Gate](https://img.shields.io/sonar/quality_gate/visus%3Anotion-sdk-ts?server=https%3A%2F%2Fsonarcloud.io&style=for-the-badge&logo=sonarcloud&logoColor=white)](https://sonarcloud.io/summary/overall?id=visus%3Anotion-sdk-ts)
6
6
  [![Sonar Coverage](https://img.shields.io/sonar/coverage/visus%3Anotion-sdk-ts?server=https%3A%2F%2Fsonarcloud.io&style=for-the-badge&logo=sonarcloud&logoColor=white)](https://sonarcloud.io/summary/overall?id=visus%3Anotion-sdk-ts)
7
7
 
8
- ![NPM Version](https://img.shields.io/npm/v/%40visus-io%2Fnotion-sdk-ts?style=for-the-badge&logo=npm)
8
+ [![NPM Version](https://img.shields.io/npm/v/%40visus-io%2Fnotion-sdk-ts?style=for-the-badge&logo=npm)](https://www.npmjs.com/package/@visus-io/notion-sdk-ts)
9
9
  ![NPM Downloads](https://img.shields.io/npm/dm/%40visus-io%2Fnotion-sdk-ts?style=for-the-badge&logo=npm)
10
10
  ![GitHub](https://img.shields.io/github/license/visus-io/notion-sdk-ts?style=for-the-badge)
11
11
 
12
12
  A type-safe TypeScript SDK for the Notion API with Zod validation, OOP models, and ergonomic helpers.
13
13
 
14
- ## Table of Contents
15
-
16
- - [Features](#features)
17
- - [Installation](#installation)
18
- - [Quick Start](#quick-start)
19
- - [Helpers](#helpers)
20
- - [Rich Text](#rich-text)
21
- - [Block Builder](#block-builder)
22
- - [Page Properties](#page-properties)
23
- - [Filters](#filters)
24
- - [Sorting](#sorting)
25
- - [Parent, Icon, Cover & File](#parent-icon-cover--file)
26
- - [Models](#models)
27
- - [Error Handling](#error-handling)
28
- - [Request Size Limits](#request-size-limits)
29
- - [Pagination](#pagination)
30
- - [Configuration](#configuration)
31
- - [API Reference](#api-reference)
32
- - [Pages](#pages-api)
33
- - [Blocks](#blocks-api)
34
- - [Databases](#databases-api)
35
- - [Data Sources](#data-sources-api)
36
- - [Comments](#comments-api)
37
- - [Search](#search-api)
38
- - [Users](#users-api)
39
- - [File Uploads](#file-uploads-api)
40
- - [TypeScript Support](#typescript-support)
41
- - [Development](#development)
42
- - [Project Structure](#project-structure)
43
-
44
14
  ## Features
45
15
 
46
16
  - **Type-safe** Zod v4 runtime validation on every API response; full TypeScript declarations
@@ -58,19 +28,12 @@ A type-safe TypeScript SDK for the Notion API with Zod validation, OOP models, a
58
28
  npm install @visus-io/notion-sdk-ts
59
29
  ```
60
30
 
31
+ **Requirements:** Node.js 18+ (uses native `fetch`)
32
+
61
33
  ## Quick Start
62
34
 
63
35
  ```typescript
64
- import {
65
- Notion,
66
- block,
67
- richText,
68
- filter,
69
- sort,
70
- prop,
71
- parent,
72
- paginate,
73
- } from '@visus-io/notion-sdk-ts';
36
+ import { Notion, block, richText, filter, sort, prop, parent } from '@visus-io/notion-sdk-ts';
74
37
 
75
38
  const notion = new Notion({ auth: process.env.NOTION_TOKEN });
76
39
 
@@ -79,13 +42,15 @@ const page = await notion.pages.retrieve('page-id');
79
42
  console.log(page.getTitle());
80
43
 
81
44
  // Create a page in a database
45
+ const database = await notion.databases.retrieve('database-id');
46
+ const dataSourceId = database.dataSources[0].id;
47
+
82
48
  await notion.pages.create({
83
- parent: parent.database('database-id'),
49
+ parent: parent.dataSource(dataSourceId, database.id),
84
50
  properties: {
85
51
  Name: prop.title('New Task'),
86
52
  Status: prop.status('In Progress'),
87
53
  Priority: prop.select('High'),
88
- 'Due Date': prop.date('2025-03-01'),
89
54
  },
90
55
  });
91
56
 
@@ -94,14 +59,11 @@ await notion.blocks.children.append('page-id', {
94
59
  children: [
95
60
  block.heading2('Meeting Notes'),
96
61
  block.paragraph('Discussed the roadmap for Q2.'),
97
- block.paragraph(richText('Action item: ').build().concat(richText('ship v2').bold().build())),
98
62
  block.toDo('Follow up with design', { checked: false }),
99
- block.divider(),
100
- block.code('console.log("hello")', 'typescript'),
101
63
  ],
102
64
  });
103
65
 
104
- // Query a database with typed filters and sorts
66
+ // Query a database with filters
105
67
  const results = await notion.databases.query('database-id', {
106
68
  filter: filter.and(
107
69
  filter.status('Status').equals('In Progress'),
@@ -109,781 +71,89 @@ const results = await notion.databases.query('database-id', {
109
71
  ),
110
72
  sorts: [sort.property('Due Date').ascending()],
111
73
  });
112
-
113
- for (const page of results.results) {
114
- console.log(page.getTitle(), page.url);
115
- }
116
-
117
- // Search across workspace
118
- const search = await notion.search.query({
119
- query: 'project planning',
120
- filter: { property: 'object', value: 'page' },
121
- });
122
- ```
123
-
124
- ## Helpers
125
-
126
- The SDK provides namespace objects that eliminate the verbose JSON the Notion API requires. All text-accepting helpers accept a `string`, a `RichTextBuilder`, or a raw `NotionRichText` array.
127
-
128
- ### Rich Text
129
-
130
- Build formatted rich text with a chainable API:
131
-
132
- ```typescript
133
- import { richText } from '@visus-io/notion-sdk-ts';
134
-
135
- // Plain text
136
- richText('Hello world').build();
137
-
138
- // Chained formatting
139
- richText('Important').bold().italic().color('red').build();
140
-
141
- // Link
142
- richText('Notion').link('https://notion.so').build();
143
-
144
- // Combine multiple segments
145
- richText.join(
146
- richText('Normal '),
147
- richText('bold').bold(),
148
- richText(' and '),
149
- richText('italic').italic(),
150
- );
151
-
152
- // Mentions
153
- richText.mentionPage('page-id').build();
154
- richText.mentionDatabase('db-id').build();
155
- richText.mentionUser({ object: 'user', id: 'user-id' }).build();
156
- richText.mentionDate('2025-03-01').build();
157
- richText.mentionLinkPreview('https://example.com').build();
158
-
159
- // Inline equation
160
- richText.equation('E=mc^2').build();
161
- ```
162
-
163
- ### Block Builder
164
-
165
- Factory functions for all 31 block types. Returns plain objects ready for `blocks.children.append()` or `pages.create()`:
166
-
167
- ```typescript
168
- import { block, richText } from '@visus-io/notion-sdk-ts';
169
-
170
- const children = [
171
- // Text blocks (accept string, RichTextBuilder, or NotionRichText)
172
- block.heading1('Title'),
173
- block.heading2('Subtitle', { isToggleable: true }),
174
- block.paragraph('Plain text'),
175
- block.paragraph(richText('Styled text').bold().color('blue')),
176
- block.bulletedListItem('First item'),
177
- block.numberedListItem('Step one'),
178
- block.toDo('Task', { checked: true }),
179
- block.toggle('Click to expand', { children: [block.paragraph('Hidden content')] }),
180
- block.quote('A wise saying'),
181
- block.callout('Heads up!', { icon: { type: 'emoji', emoji: '⚠️' } }),
182
-
183
- // Code & math
184
- block.code('const x = 42;', 'typescript', { caption: 'Example' }),
185
- block.equation('\\sum_{i=1}^{n} i'),
186
-
187
- // Media (accept URL string or FileSource object)
188
- block.image('https://example.com/photo.png', { caption: 'Photo' }),
189
- block.video('https://example.com/video.mp4'),
190
- block.audio('https://example.com/song.mp3'),
191
- block.file('https://example.com/doc.pdf'),
192
- block.pdf('https://example.com/doc.pdf'),
193
-
194
- // Embeds
195
- block.embed('https://twitter.com/example/status/123'),
196
- block.bookmark('https://example.com', { caption: 'Example site' }),
197
- block.linkPreview('https://github.com/example/repo'),
198
-
199
- // Structural
200
- block.divider(),
201
- block.breadcrumb(),
202
- block.tableOfContents(),
203
- block.table(3, {
204
- hasColumnHeader: true,
205
- children: [
206
- block.tableRow(['Name', 'Role', 'Status']),
207
- block.tableRow(['Alice', 'Engineer', 'Active']),
208
- ],
209
- }),
210
- block.columnList([[block.paragraph('Column 1')], [block.paragraph('Column 2')]]),
211
-
212
- // Synced blocks
213
- block.syncedBlock({ children: [block.paragraph('Original content')] }),
214
- block.syncedBlock({ syncedFrom: 'source-block-id' }),
215
- ];
216
- ```
217
-
218
- ### Page Properties
219
-
220
- Factory functions for setting page property values when creating or updating pages:
221
-
222
- ```typescript
223
- import { prop, richText } from '@visus-io/notion-sdk-ts';
224
-
225
- const properties = {
226
- Name: prop.title('My Task'),
227
- Description: prop.richText('Some notes'),
228
- Notes: prop.richText(richText('Important').bold()),
229
- Score: prop.number(95),
230
- Done: prop.checkbox(true),
231
- Priority: prop.select('High'),
232
- Tags: prop.multiSelect(['urgent', 'frontend']),
233
- Status: prop.status('In Progress'),
234
- 'Due Date': prop.date('2025-03-01'),
235
- 'Date Range': prop.date('2025-03-01', { end: '2025-03-15' }),
236
- Website: prop.url('https://example.com'),
237
- Contact: prop.email('user@example.com'),
238
- Phone: prop.phoneNumber('+1-555-0100'),
239
- Related: prop.relation(['page-id-1', 'page-id-2']),
240
- Assignee: prop.people(['user-id']),
241
- Attachments: prop.files([{ name: 'doc.pdf', url: 'https://example.com/doc.pdf' }]),
242
- };
243
-
244
- // Clear a property by passing null
245
- prop.select(null);
246
- prop.date(null);
247
- prop.url(null);
248
- ```
249
-
250
- ### Filters
251
-
252
- Chainable filter builders for database queries:
253
-
254
- ```typescript
255
- import { filter } from '@visus-io/notion-sdk-ts';
256
-
257
- // Single property filters
258
- filter.status('Status').equals('Active');
259
- filter.select('Priority').doesNotEqual('Low');
260
- filter.number('Score').greaterThan(80);
261
- filter.checkbox('Done').equals(false);
262
- filter.date('Due Date').before('2025-06-01');
263
- filter.date('Due Date').pastWeek();
264
- filter.text('Description').contains('important');
265
- filter.title('Name').startsWith('Project');
266
- filter.url('Website').isNotEmpty();
267
- filter.email('Contact').isNotEmpty();
268
- filter.multiSelect('Tags').contains('urgent');
269
- filter.people('Assignee').contains('user-id');
270
- filter.relation('Project').contains('page-id');
271
- filter.files('Attachments').isNotEmpty();
272
-
273
- // Timestamp filters (no property name needed)
274
- filter.createdTime().after('2025-01-01');
275
- filter.lastEditedTime().pastMonth();
276
-
277
- // Compound filters
278
- filter.and(
279
- filter.status('Status').equals('Active'),
280
- filter.number('Score').greaterThan(80),
281
- filter.or(filter.date('Due Date').before('2025-06-01'), filter.date('Due Date').isEmpty()),
282
- );
283
- ```
284
-
285
- ### Sorting
286
-
287
- ```typescript
288
- import { sort } from '@visus-io/notion-sdk-ts';
289
-
290
- const sorts = [
291
- sort.property('Priority').ascending(),
292
- sort.property('Due Date').descending(),
293
- sort.createdTime().descending(),
294
- sort.lastEditedTime().ascending(),
295
- ];
296
- ```
297
-
298
- ### Parent, Icon, Cover & File
299
-
300
- ```typescript
301
- import { parent, icon, cover, notionFile } from '@visus-io/notion-sdk-ts';
302
-
303
- // Parent objects
304
- parent.database('database-id');
305
- parent.page('page-id');
306
- parent.dataSource('data-source-id');
307
- parent.block('block-id');
308
- parent.workspace();
309
-
310
- // Icons
311
- icon.emoji('🚀');
312
- icon.external('https://example.com/icon.png');
313
- icon.fileUpload('upload-id');
314
-
315
- // Covers
316
- cover.external('https://example.com/banner.jpg');
317
- cover.fileUpload('upload-id');
318
-
319
- // File references
320
- notionFile.external('https://example.com/doc.pdf');
321
- notionFile.upload('upload-id');
322
- ```
323
-
324
- ## Models
325
-
326
- All API methods return model instances with typed properties and helper methods. Every model validates raw API data through its Zod schema on construction.
327
-
328
- ### Page
329
-
330
- ```typescript
331
- const page = await notion.pages.retrieve('page-id');
332
-
333
- page.id; // UUID
334
- page.url; // Notion URL
335
- page.publicUrl; // Public URL (if shared)
336
- page.createdTime; // Date
337
- page.lastEditedTime; // Date
338
- page.archived; // boolean
339
- page.inTrash; // boolean
340
- page.properties; // Record of property values
341
-
342
- page.getTitle(); // Plain text title
343
- page.getProperty('Name'); // Specific property value
344
- page.isInDatabase(); // true if parent is a database
345
- page.isSubpage(); // true if parent is a page
346
- page.toJSON(); // Raw validated data
347
- ```
348
-
349
- ### Block
350
-
351
- ```typescript
352
- const block = await notion.blocks.retrieve('block-id');
353
-
354
- block.id; // UUID
355
- block.type; // 'paragraph' | 'heading_1' | ...
356
- block.hasChildren; // boolean
357
-
358
- block.isTextBlock(); // paragraph, heading, list item, etc.
359
- block.isHeading(); // heading_1, heading_2, heading_3
360
- block.canHaveChildren(); // toggle, column, synced_block, etc.
361
- block.getPlainText(); // Extracted text content
362
- block.toJSON();
363
- ```
364
-
365
- ### Database
366
-
367
- ```typescript
368
- const db = await notion.databases.retrieve('database-id');
369
-
370
- db.id; // UUID
371
- db.title; // NotionRichText
372
- db.description; // NotionRichText
373
- db.dataSources; // DataSourceRef[]
374
- db.url; // Notion URL
375
- db.isInline; // boolean
376
-
377
- db.getTitle(); // Plain text title
378
- db.getDescription(); // Plain text description
379
- db.isFullPage(); // true if not inline
380
- db.hasPageParent();
381
- db.hasWorkspaceParent();
382
- db.toJSON();
383
- ```
384
-
385
- ### DataSource
386
-
387
- ```typescript
388
- const ds = await notion.dataSources.retrieve('data-source-id');
389
-
390
- ds.id; // UUID
391
- ds.properties; // Property configurations
392
-
393
- ds.getTitle();
394
- ds.getDescription();
395
- ds.getParentDatabaseId();
396
- ds.getProperty('Name'); // Specific property config
397
- ds.getPropertyNames(); // All property names
398
- ds.hasProperty('Status');
399
- ds.toJSON();
400
- ```
401
-
402
- ### User
403
-
404
- ```typescript
405
- const user = await notion.users.retrieve('user-id');
406
-
407
- user.id; // UUID
408
- user.type; // 'person' | 'bot' | undefined
409
- user.name; // string | undefined
410
- user.avatarUrl; // string | undefined
411
-
412
- user.isPerson(); // Type guard
413
- user.isBot(); // Type guard
414
- user.getEmail(); // Person users only
415
- user.getBotInfo(); // Bot users only
416
- user.toJSON();
417
- ```
418
-
419
- ### Comment
420
-
421
- ```typescript
422
- const comments = await notion.comments.list('page-id');
423
- const comment = comments.results[0];
424
-
425
- comment.id;
426
- comment.discussionId;
427
- comment.richText; // NotionRichText
428
- comment.createdTime; // Date
429
- comment.attachments;
430
- comment.displayName;
431
-
432
- comment.getPlainText();
433
- comment.hasAttachments();
434
- comment.hasCustomDisplayName();
435
- comment.getDisplayName(); // Resolved display name string
436
- comment.hasPageParent();
437
- comment.hasBlockParent();
438
- comment.toJSON();
439
- ```
440
-
441
- ### FileUpload
442
-
443
- ```typescript
444
- const upload = await notion.fileUploads.retrieve('upload-id');
445
-
446
- upload.id;
447
- upload.status; // 'pending' | 'uploaded' | 'expired' | 'failed'
448
- upload.filename;
449
- upload.contentType;
450
- upload.contentLength;
451
- upload.uploadUrl;
452
- upload.completeUrl;
453
-
454
- upload.isPending();
455
- upload.isUploaded();
456
- upload.isExpired();
457
- upload.isFailed();
458
- upload.toJSON();
459
- ```
460
-
461
- ### RichText Utility
462
-
463
- Parse and convert Notion rich text to other formats:
464
-
465
- ```typescript
466
- import { RichText } from '@visus-io/notion-sdk-ts';
467
-
468
- const rt = new RichText(page.properties.Name.title);
469
-
470
- rt.toPlainText(); // "Project Documentation"
471
- rt.toMarkdown(); // "**Project** Documentation"
472
- rt.toHTML(); // "<strong>Project</strong> Documentation"
473
- rt.hasLinks(); // boolean
474
- rt.getLinks(); // string[]
475
- rt.toJSON(); // Raw NotionRichText
476
- ```
477
-
478
- **Supported conversions:**
479
-
480
- | Format | Bold | Italic | Strikethrough | Underline | Code | Link |
481
- | -------- | ---------- | -------- | ------------- | --------- | ------------ | ------------- |
482
- | Markdown | `**text**` | `*text*` | `~~text~~` | -- | `` `text` `` | `[text](url)` |
483
- | HTML | `<strong>` | `<em>` | `<s>` | `<u>` | `<code>` | `<a href="">` |
484
-
485
- ## Error Handling
486
-
487
- Four error classes cover all failure modes:
488
-
489
- ```typescript
490
- import {
491
- NotionAPIError,
492
- NotionNetworkError,
493
- NotionRequestTimeoutError,
494
- NotionValidationError,
495
- } from '@visus-io/notion-sdk-ts';
496
-
497
- try {
498
- await notion.pages.retrieve('page-id');
499
- } catch (error) {
500
- if (error instanceof NotionValidationError) {
501
- // Client-side size limit exceeded (thrown before the request is sent)
502
- console.error(error.message);
503
- } else if (error instanceof NotionAPIError) {
504
- // Structured API error with status code and error code
505
- console.error(error.status, error.code, error.message);
506
-
507
- error.isNotFound(); // 404
508
- error.isUnauthorized(); // 401
509
- error.isValidationError(); // 400
510
- error.isRateLimited(); // 429 (auto-retried by default)
511
- error.isServerError(); // 5xx
512
- error.isRetryable(); // rate limited OR server error
513
- } else if (error instanceof NotionNetworkError) {
514
- // DNS failure, connection refused, etc.
515
- console.error(error.message, error.cause);
516
- } else if (error instanceof NotionRequestTimeoutError) {
517
- // Request exceeded configured timeout
518
- console.error(error.message);
519
- }
520
- }
521
- ```
522
-
523
- **Error codes:** `invalid_json`, `invalid_request_url`, `invalid_request`, `validation_error`, `missing_version`, `unauthorized`, `restricted_resource`, `object_not_found`, `conflict_error`, `rate_limited`, `internal_server_error`, `service_unavailable`, `database_connection_unavailable`, `gateway_timeout`
524
-
525
- ## Request Size Limits
526
-
527
- The SDK enforces [Notion API size limits](https://developers.notion.com/reference/request-limits#size-limits) client-side, throwing `NotionValidationError` before the request is sent. This applies at both layers: helpers validate when constructing objects, and API methods validate before sending.
528
-
529
- | Limit | Value | Where enforced |
530
- | ---------------------------- | ------------ | ----------------------------------------------------------------------------------------------- |
531
- | `text.content` length | 2,000 chars | `richText()`, `block.*()`, `prop.title()`, `prop.richText()` |
532
- | `text.link.url` length | 2,000 chars | `richText().link()` |
533
- | `equation.expression` length | 1,000 chars | `richText.equation()`, `block.equation()` |
534
- | Any URL property | 2,000 chars | `prop.url()`, `block.embed()`, `block.bookmark()`, `block.linkPreview()`, `block.image()`, etc. |
535
- | Email property | 200 chars | `prop.email()` |
536
- | Phone number property | 200 chars | `prop.phoneNumber()` |
537
- | Block/rich-text arrays | 100 elements | `blocks.children.append()`, `pages.create()`, `comments.create()`, `databases.create/update()` |
538
- | Multi-select options | 100 options | `prop.multiSelect()` |
539
- | Relation pages | 100 pages | `prop.relation()` |
540
- | People users | 100 users | `prop.people()` |
541
- | Comment attachments | 3 files | `comments.create()` |
542
- | `filter_properties` | 100 items | `pages.retrieve()`, `databases.retrieve/query()`, `dataSources.retrieve/query()` |
543
-
544
- All limit constants are exported as `LIMITS` for reference:
545
-
546
- ```typescript
547
- import { LIMITS } from '@visus-io/notion-sdk-ts';
548
-
549
- console.log(LIMITS.RICH_TEXT_CONTENT); // 2000
550
- console.log(LIMITS.URL); // 2000
551
- console.log(LIMITS.EMAIL); // 200
552
- console.log(LIMITS.ARRAY_ELEMENTS); // 100
553
74
  ```
554
75
 
555
- ## Pagination
556
-
557
- All list endpoints return `PaginatedList<T>` with cursor-based pagination:
558
-
559
- ```typescript
560
- interface PaginatedList<T> {
561
- results: T[];
562
- next_cursor: string | null;
563
- has_more: boolean;
564
- }
565
- ```
76
+ ## Documentation
566
77
 
567
- The SDK provides helper utilities to automatically collect all results:
78
+ Comprehensive documentation is available in the [**GitHub Wiki**](https://github.com/visus-io/notion-sdk-ts/wiki):
568
79
 
569
- ### `paginate()` - Collect all results
80
+ ### Getting Started
570
81
 
571
- Automatically fetches all pages and returns a single array:
82
+ - [**Getting Started**](https://github.com/visus-io/notion-sdk-ts/wiki/Getting-Started) - Installation, quick start, and basic configuration
83
+ - [**Migration Guide**](https://github.com/visus-io/notion-sdk-ts/wiki/Migration-Guide) - Migrating to API version 2025-09-03
84
+ - [**Common Use Cases**](https://github.com/visus-io/notion-sdk-ts/wiki/Common-Use-Cases) - Practical examples and workflows
572
85
 
573
- ```typescript
574
- import { paginate } from '@visus-io/notion-sdk-ts';
575
-
576
- // All blocks from a page
577
- const blocks = await paginate((cursor) =>
578
- notion.blocks.children.list('page-id', { start_cursor: cursor, page_size: 100 }),
579
- );
580
-
581
- // All pages from a database query
582
- const pages = await paginate((cursor) =>
583
- notion.databases.query('database-id', {
584
- start_cursor: cursor,
585
- page_size: 100,
586
- filter: filter.status('Status').equals('Active'),
587
- }),
588
- );
589
-
590
- // All comments on a page
591
- const comments = await paginate((cursor) =>
592
- notion.comments.list('page-id', { start_cursor: cursor }),
593
- );
594
-
595
- // All users in workspace
596
- const users = await paginate((cursor) => notion.users.list({ start_cursor: cursor }));
597
-
598
- // All search results
599
- const searchResults = await paginate((cursor) =>
600
- notion.search.query({
601
- query: 'project',
602
- filter: { property: 'object', value: 'page' },
603
- start_cursor: cursor,
604
- }),
605
- );
606
- ```
86
+ ### Core Concepts
607
87
 
608
- ### `paginateIterator()` - Memory-efficient iteration
88
+ - [**Helpers**](https://github.com/visus-io/notion-sdk-ts/wiki/Helpers) - Rich Text, Block Builder, Properties, Filters, Sorting
89
+ - [**Models**](https://github.com/visus-io/notion-sdk-ts/wiki/Models) - Page, Block, Database, DataSource, User, Comment, FileUpload
90
+ - [**API Reference**](https://github.com/visus-io/notion-sdk-ts/wiki/API-Reference) - Complete API endpoint documentation
609
91
 
610
- Process results one at a time without loading everything into memory:
92
+ ### Configuration & Advanced Topics
611
93
 
612
- ```typescript
613
- import { paginateIterator } from '@visus-io/notion-sdk-ts';
614
-
615
- // Process blocks one at a time
616
- for await (const block of paginateIterator((cursor) =>
617
- notion.blocks.children.list('page-id', { start_cursor: cursor }),
618
- )) {
619
- console.log(block.type, block.id);
620
- if (block.isTextBlock()) {
621
- console.log(block.getPlainText());
622
- }
623
- }
624
-
625
- // Process database pages one at a time
626
- for await (const page of paginateIterator((cursor) =>
627
- notion.databases.query('database-id', {
628
- start_cursor: cursor,
629
- filter: filter.status('Status').equals('Active'),
630
- }),
631
- )) {
632
- console.log(page.getTitle());
633
- // Process without loading all pages into memory
634
- }
635
- ```
94
+ - [**Configuration & Features**](https://github.com/visus-io/notion-sdk-ts/wiki/Configuration) - Client options, rate limiting, retries
95
+ - [**Error Handling**](https://github.com/visus-io/notion-sdk-ts/wiki/Error-Handling) - Error types, codes, and handling patterns
96
+ - [**Pagination**](https://github.com/visus-io/notion-sdk-ts/wiki/Pagination) - Automatic pagination helpers
97
+ - [**Request Size Limits**](https://github.com/visus-io/notion-sdk-ts/wiki/Request-Size-Limits) - Notion API size limits
636
98
 
637
- ### `paginateWithMetadata()` - Get results with pagination stats
99
+ ### Development
638
100
 
639
- Useful for tracking API usage and performance:
101
+ - [**TypeScript Support**](https://github.com/visus-io/notion-sdk-ts/wiki/TypeScript-Support) - Types, schemas, and type safety
102
+ - [**Development & Contributing**](https://github.com/visus-io/notion-sdk-ts/wiki/Development) - Project structure and architecture
640
103
 
641
- ```typescript
642
- import { paginateWithMetadata } from '@visus-io/notion-sdk-ts';
104
+ ## Migration Notice
643
105
 
644
- const { items, pageCount, totalCount } = await paginateWithMetadata((cursor) =>
645
- notion.blocks.children.list('page-id', { start_cursor: cursor }),
646
- );
106
+ **This SDK now defaults to Notion API version `2025-09-03`** (previously `2022-06-28`). This version introduces breaking changes for multi-source database support.
647
107
 
648
- console.log(`Fetched ${totalCount} blocks across ${pageCount} API calls`);
649
- ```
108
+ ### Key Changes
650
109
 
651
- **Paginated endpoints:** `blocks.children.list()`, `comments.list()`, `databases.query()`, `dataSources.query()`, `search.query()`, `users.list()`
110
+ - **Database creation:** Properties moved to `initial_data_source.properties`
111
+ - **Database updates:** Use Data Sources API for property changes
112
+ - **Page creation:** Requires both data source ID and database ID
113
+ - **Search API:** Returns `DataSource` objects instead of `Database`
652
114
 
653
- ## Configuration
115
+ ### Quick Migration Example
654
116
 
655
117
  ```typescript
656
- const notion = new Notion({
657
- auth: process.env.NOTION_TOKEN, // Required
658
-
659
- // All optional:
660
- baseUrl: 'https://api.notion.com', // Default
661
- notionVersion: '2022-06-28', // Default
662
- timeoutMs: 60_000, // Default: 60s
663
- retryOnRateLimit: true, // Default: true
664
- maxRetries: 3, // Default: 3
665
- fetch: customFetch, // Custom fetch implementation
118
+ // OLD (2022-06-28)
119
+ await notion.pages.create({
120
+ parent: parent.database('database-id'),
121
+ properties: { Name: prop.title('Task') },
666
122
  });
667
- ```
668
-
669
- **Rate limiting:** The SDK automatically retries 429 responses using the server's `Retry-After` header when present, falling back to exponential backoff (1s, 2s, 4s, 8s... capped at 60s) otherwise. Disable with `retryOnRateLimit: false` or adjust with `maxRetries`.
670
-
671
- ## API Reference
672
-
673
- ### Pages API
674
-
675
- | Method | Description |
676
- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
677
- | `pages.retrieve(id, options?)` | Get a page. Options: `filter_properties` (max 100) |
678
- | `pages.create(options)` | Create a page. Requires `parent` + `properties`. Optional: `icon`, `cover`, `children` (max 100), `template`, `position` |
679
- | `pages.update(id, options)` | Update properties, icon, cover, lock status, or archive state. Supports `erase_content` |
680
- | `pages.archive(id)` | Archive a page |
681
- | `pages.restore(id)` | Restore an archived page |
682
-
683
- ### Blocks API
684
-
685
- | Method | Description |
686
- | ------------------------------------- | --------------------------------------------------------- |
687
- | `blocks.retrieve(id, options?)` | Get a block |
688
- | `blocks.update(id, options)` | Update block content |
689
- | `blocks.delete(id)` | Delete (archive) a block |
690
- | `blocks.children.list(id, params?)` | List child blocks (paginated) |
691
- | `blocks.children.append(id, options)` | Append child blocks (max 100). Optional: `after` block ID |
692
-
693
- ### Databases API
694
-
695
- | Method | Description |
696
- | ---------------------------------- | ----------------------------------------------------------------------- |
697
- | `databases.retrieve(id, options?)` | Get a database |
698
- | `databases.query(id, options?)` | Query with `filter`, `sorts`, pagination. Returns `PaginatedList<Page>` |
699
- | `databases.create(options)` | Create a database. Requires `parent` + `properties` |
700
- | `databases.update(id, options)` | Update title, description, properties, icon, cover |
701
- | `databases.archive(id)` | Archive a database |
702
- | `databases.restore(id)` | Restore a database |
703
-
704
- ### Data Sources API
705
-
706
- Data sources represent individual tables under databases (API version 2025-09-03).
707
-
708
- | Method | Description |
709
- | ----------------------------------------- | -------------------------------------------------------------------- |
710
- | `dataSources.retrieve(id, options?)` | Get a data source |
711
- | `dataSources.query(id, options?)` | Query with filters/sorts. `result_type`: `'page'` or `'data_source'` |
712
- | `dataSources.create(options)` | Create a data source under a database |
713
- | `dataSources.update(id, options)` | Update a data source |
714
- | `dataSources.archive(id)` / `restore(id)` | Archive/restore |
715
- | `dataSources.trash(id)` / `untrash(id)` | Move to/from trash |
716
-
717
- ### Comments API
718
-
719
- | Method | Description |
720
- | ---------------------------------- | -------------------------------------------------------------------------------------------------------- |
721
- | `comments.list(parentId, params?)` | List comments on a page/block (paginated) |
722
- | `comments.create(options)` | Create a comment. Options: `parent`, `rich_text`, `discussion_id`, `attachments` (max 3), `display_name` |
723
-
724
- ### Search API
725
-
726
- | Method | Description |
727
- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
728
- | `search.query(options?)` | Search workspace. Filter by `'page'` or `'database'`. Sort by `last_edited_time`. Returns `PaginatedList<Page \| Database>` |
729
-
730
- ### Users API
731
-
732
- | Method | Description |
733
- | --------------------- | -------------------------------------- |
734
- | `users.list(params?)` | List all workspace users (paginated) |
735
- | `users.retrieve(id)` | Get a user by ID |
736
- | `users.me()` | Get the bot user for the current token |
737
123
 
738
- ### File Uploads API
739
-
740
- | Method | Description |
741
- | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
742
- | `fileUploads.uploadFile(filename, data, contentType)` | Upload a file in one call (handles initiate + upload + complete). `data`: `Buffer \| ArrayBuffer \| Blob` |
743
- | `fileUploads.initiate(options)` | Step 1: Initiate upload |
744
- | `fileUploads.upload(url, data, contentType)` | Step 2: Upload file data |
745
- | `fileUploads.complete(url)` | Step 3: Mark upload complete |
746
- | `fileUploads.retrieve(id)` | Check upload status |
747
-
748
- **Full example:**
749
-
750
- ```typescript
751
- import { readFileSync } from 'fs';
752
-
753
- // One-step upload
754
- const upload = await notion.fileUploads.uploadFile(
755
- 'document.pdf',
756
- readFileSync('./document.pdf'),
757
- 'application/pdf',
758
- );
759
-
760
- console.log(upload.status); // 'uploaded'
124
+ // NEW (2025-09-03)
125
+ const db = await notion.databases.retrieve('database-id');
126
+ const dataSourceId = db.dataSources[0].id;
761
127
 
762
- // Or multi-step for more control
763
- const init = await notion.fileUploads.initiate({
764
- name: 'doc.pdf',
765
- content_type: 'application/pdf',
128
+ await notion.pages.create({
129
+ parent: parent.dataSource(dataSourceId, db.id),
130
+ properties: { Name: prop.title('Task') },
766
131
  });
767
- await notion.fileUploads.upload(init.uploadUrl, fileData, 'application/pdf');
768
- const completed = await notion.fileUploads.complete(init.completeUrl);
769
- ```
770
-
771
- ## TypeScript Support
772
-
773
- All Zod schemas and their inferred types are exported:
774
-
775
- ```typescript
776
- import type {
777
- NotionPage,
778
- NotionBlock,
779
- NotionDatabase,
780
- NotionUser,
781
- NotionComment,
782
- NotionDataSource,
783
- NotionFileUpload,
784
- NotionRichText,
785
- NotionParent,
786
- NotionFile,
787
- NotionColor,
788
- PaginatedList,
789
- } from '@visus-io/notion-sdk-ts';
790
-
791
- // Model classes
792
- import type {
793
- Page,
794
- Block,
795
- Database,
796
- User,
797
- Comment,
798
- DataSource,
799
- FileUpload,
800
- } from '@visus-io/notion-sdk-ts';
801
-
802
- // Zod schemas for manual validation
803
- import { pageSchema, blockSchema, databaseSchema, userSchema } from '@visus-io/notion-sdk-ts';
804
-
805
- const validated = pageSchema.parse(rawData);
806
132
  ```
807
133
 
808
- **Supported block types (31):** paragraph, heading_1/2/3, bulleted_list_item, numbered_list_item, to_do, toggle, quote, callout, code, template, image, video, audio, file, pdf, bookmark, embed, child_database, child_page, column_list, column, divider, table_of_contents, breadcrumb, table, table_row, link_preview, synced_block, equation, unsupported
809
-
810
- **Supported property types (21):** title, rich_text, number, checkbox, date, url, email, phone_number, select, multi_select, status, relation, rollup, people, created_by, last_edited_by, created_time, last_edited_time, files, formula, unique_id, verification
134
+ See the [**Migration Guide**](https://github.com/visus-io/notion-sdk-ts/wiki/Migration-Guide) for complete details.
811
135
 
812
136
  ## Development
813
137
 
814
138
  ```bash
815
139
  npm install # Install dependencies
816
- npm run build # Compile TypeScript to dist/
140
+ npm run build # Compile TypeScript
817
141
 
818
- npm test # Run tests (Vitest)
142
+ npm test # Run tests
819
143
  npm run test:watch # Watch mode
820
- npm run test:coverage # Coverage report (v8)
144
+ npm run test:coverage # Coverage report
821
145
 
822
146
  npm run lint # ESLint
823
- npm run lint:fix # Auto-fix lint issues
147
+ npm run lint:fix # Auto-fix
824
148
  npm run format # Prettier
825
- npm run format:check # Check formatting
826
- ```
827
-
828
- ## Project Structure
829
-
830
- ```
831
- src/
832
- ├── index.ts # Entry point — re-exports everything
833
- ├── notion.ts # Notion class (main SDK entry)
834
- ├── client.ts # HTTP client with retry logic
835
- ├── errors.ts # NotionAPIError, NotionNetworkError, NotionRequestTimeoutError
836
- ├── validation.ts # NotionValidationError, LIMITS, size-limit validators
837
- ├── api/
838
- │ ├── blocks.api.ts # Blocks API
839
- │ ├── comments.api.ts # Comments API
840
- │ ├── databases.api.ts # Databases API
841
- │ ├── dataSources.api.ts # Data Sources API
842
- │ ├── fileUploads.api.ts # File Uploads API
843
- │ ├── pages.api.ts # Pages API
844
- │ ├── search.api.ts # Search API
845
- │ └── users.api.ts # Users API
846
- ├── helpers/
847
- │ ├── block.helpers.ts # block.paragraph(), block.heading1(), etc.
848
- │ ├── richText.helpers.ts # richText(), RichTextBuilder
849
- │ ├── filter.helpers.ts # filter.status(), filter.and(), etc.
850
- │ ├── sort.helpers.ts # sort.property(), sort.createdTime()
851
- │ ├── property.helpers.ts # prop.title(), prop.select(), etc.
852
- │ ├── parent.helpers.ts # parent.database(), parent.page()
853
- │ └── file.helpers.ts # icon, cover, notionFile
854
- ├── models/
855
- │ ├── base.model.ts # Abstract BaseModel<T> with Zod validation
856
- │ ├── page.model.ts # Page
857
- │ ├── block.model.ts # Block
858
- │ ├── database.model.ts # Database
859
- │ ├── dataSource.model.ts # DataSource
860
- │ ├── comment.model.ts # Comment
861
- │ ├── user.model.ts # User
862
- │ ├── fileUpload.model.ts # FileUpload
863
- │ └── richText.model.ts # RichText (toPlainText/toMarkdown/toHTML)
864
- └── schemas/
865
- ├── page.schema.ts # pageSchema + NotionPage
866
- ├── block.schema.ts # blockSchema + NotionBlock (31 types)
867
- ├── database.schema.ts # databaseSchema + NotionDatabase
868
- ├── dataSource.schema.ts # dataSourceSchema + NotionDataSource
869
- ├── comment.schema.ts # commentSchema + NotionComment
870
- ├── user.schema.ts # userSchema + NotionUser
871
- ├── fileUpload.schema.ts # fileUploadSchema + NotionFileUpload
872
- ├── pageProperties.schema.ts # 21 page property value types
873
- ├── propertyObjects.schema.ts# 21 database property config types
874
- ├── richText.schema.ts # richTextSchema + 3 types + 6 mention types
875
- ├── pagination.schema.ts # PaginatedList<T>, PaginationParameters
876
- ├── parent.schema.ts # 5 parent types
877
- ├── file.schema.ts # 3 file variants
878
- ├── emoji.schema.ts # NotionEmoji
879
- ├── colors.ts # NOTION_COLORS (19 colors)
880
- └── codeLanguages.ts # CODE_BLOCK_LANGUAGES (75 languages)
881
149
  ```
882
150
 
883
- **Architecture:** `Notion` (facade) -> `*API` classes (endpoint logic + Zod parsing) -> `NotionClient` (HTTP transport with retry). Every API response is validated through its Zod schema before being wrapped in a model class.
151
+ See [**Development & Contributing**](https://github.com/visus-io/notion-sdk-ts/wiki/Development) for more details.
884
152
 
885
153
  ## Links
886
154
 
887
- - [Notion API Documentation](https://developers.notion.com/reference/intro)
888
- - [Notion API Changelog](https://developers.notion.com/page/changelog)
889
- - [GitHub Repository](https://github.com/visus-io/notion-sdk-ts)
155
+ - [**Documentation Wiki**](https://github.com/visus-io/notion-sdk-ts/wiki)
156
+ - [**GitHub Repository**](https://github.com/visus-io/notion-sdk-ts)
157
+ - [**npm Package**](https://www.npmjs.com/package/@visus-io/notion-sdk-ts)
158
+ - [**Notion API Documentation**](https://developers.notion.com/reference/intro)
159
+ - [**Notion API Changelog**](https://developers.notion.com/page/changelog)