@catafal/notion-cli 5.9.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 (162) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +552 -0
  3. package/bin/dev +17 -0
  4. package/bin/dev.cmd +3 -0
  5. package/bin/run +14 -0
  6. package/bin/run.cmd +3 -0
  7. package/dist/base-command.d.ts +73 -0
  8. package/dist/base-command.js +179 -0
  9. package/dist/base-flags.d.ts +14 -0
  10. package/dist/base-flags.js +59 -0
  11. package/dist/cache.d.ts +84 -0
  12. package/dist/cache.js +351 -0
  13. package/dist/commands/append.d.ts +37 -0
  14. package/dist/commands/append.js +120 -0
  15. package/dist/commands/batch/delete.d.ts +42 -0
  16. package/dist/commands/batch/delete.js +199 -0
  17. package/dist/commands/batch/retrieve.d.ts +43 -0
  18. package/dist/commands/batch/retrieve.js +272 -0
  19. package/dist/commands/block/append.d.ts +42 -0
  20. package/dist/commands/block/append.js +219 -0
  21. package/dist/commands/block/delete.d.ts +30 -0
  22. package/dist/commands/block/delete.js +97 -0
  23. package/dist/commands/block/retrieve/children.d.ts +31 -0
  24. package/dist/commands/block/retrieve/children.js +177 -0
  25. package/dist/commands/block/retrieve.d.ts +30 -0
  26. package/dist/commands/block/retrieve.js +101 -0
  27. package/dist/commands/block/update.d.ts +45 -0
  28. package/dist/commands/block/update.js +242 -0
  29. package/dist/commands/bookmark/list.d.ts +30 -0
  30. package/dist/commands/bookmark/list.js +60 -0
  31. package/dist/commands/bookmark/remove.d.ts +26 -0
  32. package/dist/commands/bookmark/remove.js +47 -0
  33. package/dist/commands/bookmark/set.d.ts +29 -0
  34. package/dist/commands/bookmark/set.js +96 -0
  35. package/dist/commands/browse.d.ts +13 -0
  36. package/dist/commands/browse.js +44 -0
  37. package/dist/commands/cache/info.d.ts +19 -0
  38. package/dist/commands/cache/info.js +145 -0
  39. package/dist/commands/config/set-token.d.ts +22 -0
  40. package/dist/commands/config/set-token.js +137 -0
  41. package/dist/commands/daily/index.d.ts +32 -0
  42. package/dist/commands/daily/index.js +135 -0
  43. package/dist/commands/daily/setup.d.ts +42 -0
  44. package/dist/commands/daily/setup.js +149 -0
  45. package/dist/commands/db/create.d.ts +31 -0
  46. package/dist/commands/db/create.js +124 -0
  47. package/dist/commands/db/query.d.ts +41 -0
  48. package/dist/commands/db/query.js +360 -0
  49. package/dist/commands/db/retrieve.d.ts +33 -0
  50. package/dist/commands/db/retrieve.js +134 -0
  51. package/dist/commands/db/schema.d.ts +32 -0
  52. package/dist/commands/db/schema.js +308 -0
  53. package/dist/commands/db/update.d.ts +31 -0
  54. package/dist/commands/db/update.js +117 -0
  55. package/dist/commands/doctor.d.ts +50 -0
  56. package/dist/commands/doctor.js +420 -0
  57. package/dist/commands/init.d.ts +65 -0
  58. package/dist/commands/init.js +479 -0
  59. package/dist/commands/list.d.ts +29 -0
  60. package/dist/commands/list.js +219 -0
  61. package/dist/commands/open.d.ts +29 -0
  62. package/dist/commands/open.js +100 -0
  63. package/dist/commands/page/create.d.ts +33 -0
  64. package/dist/commands/page/create.js +261 -0
  65. package/dist/commands/page/delete.d.ts +36 -0
  66. package/dist/commands/page/delete.js +107 -0
  67. package/dist/commands/page/export.d.ts +38 -0
  68. package/dist/commands/page/export.js +120 -0
  69. package/dist/commands/page/retrieve/property_item.d.ts +24 -0
  70. package/dist/commands/page/retrieve/property_item.js +75 -0
  71. package/dist/commands/page/retrieve.d.ts +36 -0
  72. package/dist/commands/page/retrieve.js +244 -0
  73. package/dist/commands/page/update.d.ts +34 -0
  74. package/dist/commands/page/update.js +184 -0
  75. package/dist/commands/quick.d.ts +35 -0
  76. package/dist/commands/quick.js +168 -0
  77. package/dist/commands/search.d.ts +43 -0
  78. package/dist/commands/search.js +361 -0
  79. package/dist/commands/stats.d.ts +35 -0
  80. package/dist/commands/stats.js +274 -0
  81. package/dist/commands/sync.d.ts +24 -0
  82. package/dist/commands/sync.js +183 -0
  83. package/dist/commands/template/get.d.ts +28 -0
  84. package/dist/commands/template/get.js +59 -0
  85. package/dist/commands/template/list.d.ts +32 -0
  86. package/dist/commands/template/list.js +62 -0
  87. package/dist/commands/template/remove.d.ts +27 -0
  88. package/dist/commands/template/remove.js +48 -0
  89. package/dist/commands/template/save.d.ts +32 -0
  90. package/dist/commands/template/save.js +92 -0
  91. package/dist/commands/template/use.d.ts +34 -0
  92. package/dist/commands/template/use.js +142 -0
  93. package/dist/commands/user/list.d.ts +27 -0
  94. package/dist/commands/user/list.js +99 -0
  95. package/dist/commands/user/retrieve/bot.d.ts +28 -0
  96. package/dist/commands/user/retrieve/bot.js +96 -0
  97. package/dist/commands/user/retrieve.d.ts +30 -0
  98. package/dist/commands/user/retrieve.js +103 -0
  99. package/dist/commands/whoami.d.ts +19 -0
  100. package/dist/commands/whoami.js +175 -0
  101. package/dist/deduplication.d.ts +41 -0
  102. package/dist/deduplication.js +71 -0
  103. package/dist/envelope.d.ts +169 -0
  104. package/dist/envelope.js +257 -0
  105. package/dist/errors/enhanced-errors.d.ts +168 -0
  106. package/dist/errors/enhanced-errors.js +567 -0
  107. package/dist/errors/index.d.ts +18 -0
  108. package/dist/errors/index.js +33 -0
  109. package/dist/examples/cache-retry-examples.d.ts +64 -0
  110. package/dist/examples/cache-retry-examples.js +375 -0
  111. package/dist/helper.d.ts +102 -0
  112. package/dist/helper.js +885 -0
  113. package/dist/http-agent.d.ts +38 -0
  114. package/dist/http-agent.js +60 -0
  115. package/dist/index.d.ts +1 -0
  116. package/dist/index.js +4 -0
  117. package/dist/interface.d.ts +4 -0
  118. package/dist/interface.js +2 -0
  119. package/dist/notion.d.ts +144 -0
  120. package/dist/notion.js +547 -0
  121. package/dist/retry.d.ts +72 -0
  122. package/dist/retry.js +381 -0
  123. package/dist/utils/bookmarks.d.ts +32 -0
  124. package/dist/utils/bookmarks.js +98 -0
  125. package/dist/utils/daily-config.d.ts +22 -0
  126. package/dist/utils/daily-config.js +60 -0
  127. package/dist/utils/disk-cache.d.ts +80 -0
  128. package/dist/utils/disk-cache.js +291 -0
  129. package/dist/utils/fuzzy.d.ts +36 -0
  130. package/dist/utils/fuzzy.js +69 -0
  131. package/dist/utils/interactive-navigator.d.ts +63 -0
  132. package/dist/utils/interactive-navigator.js +123 -0
  133. package/dist/utils/markdown-to-blocks.d.ts +21 -0
  134. package/dist/utils/markdown-to-blocks.js +333 -0
  135. package/dist/utils/notion-resolver.d.ts +49 -0
  136. package/dist/utils/notion-resolver.js +278 -0
  137. package/dist/utils/notion-url-parser.d.ts +48 -0
  138. package/dist/utils/notion-url-parser.js +121 -0
  139. package/dist/utils/property-expander.d.ts +45 -0
  140. package/dist/utils/property-expander.js +323 -0
  141. package/dist/utils/schema-examples.d.ts +40 -0
  142. package/dist/utils/schema-examples.js +359 -0
  143. package/dist/utils/schema-extractor.d.ts +65 -0
  144. package/dist/utils/schema-extractor.js +235 -0
  145. package/dist/utils/shell-config.d.ts +30 -0
  146. package/dist/utils/shell-config.js +84 -0
  147. package/dist/utils/table-formatter.d.ts +36 -0
  148. package/dist/utils/table-formatter.js +125 -0
  149. package/dist/utils/templates.d.ts +30 -0
  150. package/dist/utils/templates.js +82 -0
  151. package/dist/utils/terminal-banner.d.ts +24 -0
  152. package/dist/utils/terminal-banner.js +34 -0
  153. package/dist/utils/token-validator.d.ts +42 -0
  154. package/dist/utils/token-validator.js +66 -0
  155. package/dist/utils/update-notifier.d.ts +26 -0
  156. package/dist/utils/update-notifier.js +54 -0
  157. package/dist/utils/workspace-cache.d.ts +58 -0
  158. package/dist/utils/workspace-cache.js +185 -0
  159. package/oclif.manifest.json +6471 -0
  160. package/package.json +118 -0
  161. package/scripts/banner.js +38 -0
  162. package/scripts/postinstall.js +44 -0
package/dist/helper.js ADDED
@@ -0,0 +1,885 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildBlockUpdateFromTextFlags = exports.getChildDatabasesWithIds = exports.enrichChildDatabaseBlock = exports.buildBlocksFromTextFlags = exports.getBlockPlainText = exports.getPageTitle = exports.getDataSourceTitle = exports.getDbTitle = exports.buildOneDepthJson = exports.buildPagePropUpdateData = exports.buildDatabaseQueryFilter = exports.getFilterFields = exports.outputPrettyTable = exports.outputMarkdownTable = exports.stripMetadata = exports.outputCompactJson = exports.outputRawJson = void 0;
4
+ exports.showRawFlagHint = showRawFlagHint;
5
+ const notion = require("./notion");
6
+ const client_1 = require("@notionhq/client");
7
+ const outputRawJson = async (res) => {
8
+ console.log(JSON.stringify(res, null, 2));
9
+ };
10
+ exports.outputRawJson = outputRawJson;
11
+ /**
12
+ * Output data as compact JSON (single-line, no formatting)
13
+ * Useful for piping to other tools or scripts
14
+ */
15
+ const outputCompactJson = (res) => {
16
+ console.log(JSON.stringify(res));
17
+ };
18
+ exports.outputCompactJson = outputCompactJson;
19
+ /**
20
+ * Strip unnecessary metadata from Notion API responses to reduce size
21
+ * Removes created_by, last_edited_by, object fields, request_id, empty values, etc.
22
+ * Keeps timestamps (created_time, last_edited_time) and essential data
23
+ *
24
+ * @param data The data to strip metadata from (single object or array)
25
+ * @returns The stripped data
26
+ */
27
+ const stripMetadata = (data) => {
28
+ if (Array.isArray(data)) {
29
+ return data.map(item => (0, exports.stripMetadata)(item));
30
+ }
31
+ if (data === null || typeof data !== 'object') {
32
+ return data;
33
+ }
34
+ const result = {};
35
+ for (const [key, value] of Object.entries(data)) {
36
+ // Skip fields that should be removed
37
+ if (key === 'created_by' ||
38
+ key === 'last_edited_by' ||
39
+ key === 'request_id' ||
40
+ key === 'object' ||
41
+ (key === 'has_more' && value === false)) {
42
+ continue;
43
+ }
44
+ // Skip empty arrays
45
+ if (Array.isArray(value) && value.length === 0) {
46
+ continue;
47
+ }
48
+ // Skip empty objects (but keep objects with properties)
49
+ if (value && typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0) {
50
+ continue;
51
+ }
52
+ // Recursively strip metadata from nested objects and arrays
53
+ if (value && typeof value === 'object') {
54
+ result[key] = (0, exports.stripMetadata)(value);
55
+ }
56
+ else {
57
+ result[key] = value;
58
+ }
59
+ }
60
+ return result;
61
+ };
62
+ exports.stripMetadata = stripMetadata;
63
+ /**
64
+ * Output data as a markdown table
65
+ * Converts column data into GitHub-flavored markdown table format
66
+ */
67
+ const outputMarkdownTable = (data, columns) => {
68
+ if (!data || data.length === 0) {
69
+ console.log('No data to display');
70
+ return;
71
+ }
72
+ // Extract column headers
73
+ const headers = Object.keys(columns);
74
+ // Build header row
75
+ const headerRow = '| ' + headers.join(' | ') + ' |';
76
+ const separatorRow = '| ' + headers.map(() => '---').join(' | ') + ' |';
77
+ console.log(headerRow);
78
+ console.log(separatorRow);
79
+ // Build data rows
80
+ data.forEach((row) => {
81
+ const values = headers.map((header) => {
82
+ const column = columns[header];
83
+ let value;
84
+ // Handle column getter function
85
+ if (column.get && typeof column.get === 'function') {
86
+ value = column.get(row);
87
+ }
88
+ else if (column.header) {
89
+ // If column has a header property, use the key to get value
90
+ value = row[header];
91
+ }
92
+ else {
93
+ // Direct property access
94
+ value = row[header];
95
+ }
96
+ // Format value for markdown (escape pipes and handle nulls)
97
+ if (value === null || value === undefined) {
98
+ return '';
99
+ }
100
+ const stringValue = String(value).replace(/\|/g, '\\|').replace(/\n/g, ' ');
101
+ return stringValue;
102
+ });
103
+ console.log('| ' + values.join(' | ') + ' |');
104
+ });
105
+ };
106
+ exports.outputMarkdownTable = outputMarkdownTable;
107
+ /**
108
+ * Output data as a pretty table with borders
109
+ * Enhanced table format with better visual separation
110
+ */
111
+ const outputPrettyTable = (data, columns) => {
112
+ if (!data || data.length === 0) {
113
+ console.log('No data to display');
114
+ return;
115
+ }
116
+ const headers = Object.keys(columns);
117
+ // Calculate column widths
118
+ const columnWidths = {};
119
+ headers.forEach((header) => {
120
+ columnWidths[header] = header.length;
121
+ });
122
+ // Calculate max width for each column based on data
123
+ data.forEach((row) => {
124
+ headers.forEach((header) => {
125
+ const column = columns[header];
126
+ let value;
127
+ if (column.get && typeof column.get === 'function') {
128
+ value = column.get(row);
129
+ }
130
+ else {
131
+ value = row[header];
132
+ }
133
+ const stringValue = String(value === null || value === undefined ? '' : value);
134
+ columnWidths[header] = Math.max(columnWidths[header], stringValue.length);
135
+ });
136
+ });
137
+ // Build separator line
138
+ const topBorder = '┌' + headers.map(h => '─'.repeat(columnWidths[h] + 2)).join('┬') + '┐';
139
+ const headerSeparator = '├' + headers.map(h => '─'.repeat(columnWidths[h] + 2)).join('┼') + '┤';
140
+ const bottomBorder = '└' + headers.map(h => '─'.repeat(columnWidths[h] + 2)).join('┴') + '┘';
141
+ // Print top border
142
+ console.log(topBorder);
143
+ // Print headers
144
+ const headerRow = '│ ' + headers.map(h => h.padEnd(columnWidths[h])).join(' │ ') + ' │';
145
+ console.log(headerRow);
146
+ console.log(headerSeparator);
147
+ // Print data rows
148
+ data.forEach((row) => {
149
+ const values = headers.map((header) => {
150
+ const column = columns[header];
151
+ let value;
152
+ if (column.get && typeof column.get === 'function') {
153
+ value = column.get(row);
154
+ }
155
+ else {
156
+ value = row[header];
157
+ }
158
+ const stringValue = String(value === null || value === undefined ? '' : value);
159
+ return stringValue.padEnd(columnWidths[header]);
160
+ });
161
+ console.log('│ ' + values.join(' │ ') + ' │');
162
+ });
163
+ // Print bottom border
164
+ console.log(bottomBorder);
165
+ };
166
+ exports.outputPrettyTable = outputPrettyTable;
167
+ /**
168
+ * Show a hint to users (especially AI assistants) that more data is available with the -r flag
169
+ * This makes the -r flag more discoverable for automation and AI use cases
170
+ *
171
+ * @param itemCount Number of items displayed in the table
172
+ * @param item The item object to count total fields from
173
+ * @param visibleFields Number of fields shown in the table (default: 4 for title, object, id, url)
174
+ */
175
+ function showRawFlagHint(itemCount, item, visibleFields = 4) {
176
+ // Count total fields in the item
177
+ let totalFields = visibleFields; // Start with the visible fields (title, object, id, url)
178
+ if (item) {
179
+ // For pages and databases, count properties
180
+ if (item.properties) {
181
+ totalFields += Object.keys(item.properties).length;
182
+ }
183
+ // Add other top-level metadata fields
184
+ const metadataFields = ['created_time', 'last_edited_time', 'created_by', 'last_edited_by', 'parent', 'archived', 'icon', 'cover'];
185
+ metadataFields.forEach(field => {
186
+ if (item[field] !== undefined) {
187
+ totalFields++;
188
+ }
189
+ });
190
+ }
191
+ const hiddenFields = totalFields - visibleFields;
192
+ if (hiddenFields > 0) {
193
+ const itemText = itemCount === 1 ? 'item' : 'items';
194
+ console.log(`\nTip: Showing ${visibleFields} of ${totalFields} fields for ${itemCount} ${itemText}.`);
195
+ console.log(`Use -r flag for full JSON output with all properties (recommended for AI assistants and automation).`);
196
+ }
197
+ }
198
+ const getFilterFields = async (type) => {
199
+ switch (type) {
200
+ case 'checkbox':
201
+ return [{ title: 'equals' }, { title: 'does_not_equal' }];
202
+ case 'created_time':
203
+ case 'last_edited_time':
204
+ case 'date':
205
+ return [
206
+ { title: 'after' },
207
+ { title: 'before' },
208
+ { title: 'equals' },
209
+ { title: 'is_empty' },
210
+ { title: 'is_not_empty' },
211
+ { title: 'next_month' },
212
+ { title: 'next_week' },
213
+ { title: 'next_year' },
214
+ { title: 'on_or_after' },
215
+ { title: 'on_or_before' },
216
+ { title: 'past_month' },
217
+ { title: 'past_week' },
218
+ { title: 'past_year' },
219
+ { title: 'this_week' },
220
+ ];
221
+ case 'rich_text':
222
+ case 'title':
223
+ return [
224
+ { title: 'contains' },
225
+ { title: 'does_not_contain' },
226
+ { title: 'does_not_equal' },
227
+ { title: 'ends_with' },
228
+ { title: 'equals' },
229
+ { title: 'is_empty' },
230
+ { title: 'is_not_empty' },
231
+ { title: 'starts_with' },
232
+ ];
233
+ case 'number':
234
+ return [
235
+ { title: 'equals' },
236
+ { title: 'does_not_equal' },
237
+ { title: 'greater_than' },
238
+ { title: 'greater_than_or_equal_to' },
239
+ { title: 'less_than' },
240
+ { title: 'less_than_or_equal_to' },
241
+ { title: 'is_empty' },
242
+ { title: 'is_not_empty' },
243
+ ];
244
+ case 'select':
245
+ return [
246
+ { title: 'equals' },
247
+ { title: 'does_not_equal' },
248
+ { title: 'is_empty' },
249
+ { title: 'is_not_empty' },
250
+ ];
251
+ case 'multi_select':
252
+ case 'relation':
253
+ return [
254
+ { title: 'contains' },
255
+ { title: 'does_not_contain' },
256
+ { title: 'is_empty' },
257
+ { title: 'is_not_empty' },
258
+ ];
259
+ case 'status':
260
+ return [
261
+ { title: 'equals' },
262
+ { title: 'does_not_equal' },
263
+ { title: 'is_empty' },
264
+ { title: 'is_not_empty' },
265
+ ];
266
+ case 'files':
267
+ case 'formula':
268
+ case 'people':
269
+ case 'rollup':
270
+ default:
271
+ console.error(`type: ${type} is not support type`);
272
+ return null;
273
+ }
274
+ };
275
+ exports.getFilterFields = getFilterFields;
276
+ const buildDatabaseQueryFilter = async (name, type, field, value) => {
277
+ let filter = null;
278
+ switch (type) {
279
+ case 'checkbox':
280
+ filter = {
281
+ property: name,
282
+ [type]: {
283
+ // boolean value
284
+ [field]: value == 'true',
285
+ },
286
+ };
287
+ break;
288
+ case 'date':
289
+ case 'created_time':
290
+ case 'last_edited_time':
291
+ case 'rich_text':
292
+ case 'number':
293
+ case 'select':
294
+ case 'status':
295
+ case 'title':
296
+ filter = {
297
+ property: name,
298
+ [type]: {
299
+ [field]: value,
300
+ },
301
+ };
302
+ break;
303
+ case 'multi_select':
304
+ case 'relation': {
305
+ const values = value;
306
+ if (values.length == 1) {
307
+ filter = {
308
+ property: name,
309
+ [type]: {
310
+ [field]: value[0],
311
+ },
312
+ };
313
+ }
314
+ else {
315
+ filter = { and: [] };
316
+ for (const v of values) {
317
+ filter.and.push({
318
+ property: name,
319
+ [type]: {
320
+ [field]: v,
321
+ },
322
+ });
323
+ }
324
+ }
325
+ break;
326
+ }
327
+ case 'files':
328
+ case 'formula':
329
+ case 'people':
330
+ case 'rollup':
331
+ default:
332
+ console.error(`type: ${type} is not support type`);
333
+ }
334
+ return filter;
335
+ };
336
+ exports.buildDatabaseQueryFilter = buildDatabaseQueryFilter;
337
+ const buildPagePropUpdateData = async (name, type, value) => {
338
+ switch (type) {
339
+ case 'number':
340
+ return {
341
+ [name]: {
342
+ [type]: value,
343
+ },
344
+ };
345
+ case 'select':
346
+ return {
347
+ [name]: {
348
+ [type]: {
349
+ name: value,
350
+ },
351
+ },
352
+ };
353
+ case 'multi_select': {
354
+ const nameObjects = [];
355
+ for (const val of value) {
356
+ nameObjects.push({
357
+ name: val,
358
+ });
359
+ }
360
+ return {
361
+ [name]: {
362
+ [type]: nameObjects,
363
+ },
364
+ };
365
+ }
366
+ case 'relation': {
367
+ const relationPageIds = [];
368
+ for (const id of value) {
369
+ relationPageIds.push({ id: id });
370
+ }
371
+ return {
372
+ [name]: {
373
+ [type]: relationPageIds,
374
+ },
375
+ };
376
+ }
377
+ }
378
+ return null;
379
+ };
380
+ exports.buildPagePropUpdateData = buildPagePropUpdateData;
381
+ const buildOneDepthJson = async (pages) => {
382
+ const oneDepthJson = [];
383
+ const relationJson = [];
384
+ for (const page of pages) {
385
+ if (page.object != 'page') {
386
+ continue;
387
+ }
388
+ if (!(0, client_1.isFullPage)(page)) {
389
+ continue;
390
+ }
391
+ const pageData = {};
392
+ pageData['page_id'] = page.id;
393
+ Object.entries(page.properties).forEach(([key, prop]) => {
394
+ switch (prop.type) {
395
+ case 'number':
396
+ pageData[key] = prop.number;
397
+ break;
398
+ case 'select':
399
+ pageData[key] = prop.select === null ? '' : prop.select.name;
400
+ break;
401
+ case 'multi_select': {
402
+ const multiSelects = [];
403
+ for (const select of prop.multi_select) {
404
+ multiSelects.push(select.name);
405
+ }
406
+ pageData[key] = multiSelects.join(',');
407
+ break;
408
+ }
409
+ case 'relation': {
410
+ const relationPages = [];
411
+ // relationJsonにkeyがなければ作成
412
+ if (relationJson[key] == null) {
413
+ relationJson[key] = [];
414
+ }
415
+ for (const relation of prop.relation) {
416
+ relationPages.push(relation.id);
417
+ relationJson[key].push({
418
+ page_id: page.id,
419
+ relation_page_id: relation.id,
420
+ });
421
+ }
422
+ pageData[key] = relationPages.join(',');
423
+ break;
424
+ }
425
+ case 'created_time':
426
+ pageData[key] = prop.created_time;
427
+ break;
428
+ case 'last_edited_time':
429
+ pageData[key] = prop.last_edited_time;
430
+ break;
431
+ case 'formula':
432
+ switch (prop.formula.type) {
433
+ case 'string':
434
+ pageData[key] = prop.formula.string;
435
+ break;
436
+ case 'number':
437
+ pageData[key] = prop.formula.number;
438
+ break;
439
+ case 'boolean':
440
+ pageData[key] = prop.formula.boolean;
441
+ break;
442
+ case 'date':
443
+ pageData[key] = prop.formula.date.start;
444
+ break;
445
+ default:
446
+ // console.error(`${prop.formula.type} is not supported`)
447
+ }
448
+ break;
449
+ case 'url':
450
+ pageData[key] = prop.url;
451
+ break;
452
+ case 'date':
453
+ pageData[key] = prop.date === null ? '' : prop.date.start;
454
+ break;
455
+ case 'email':
456
+ pageData[key] = prop.email;
457
+ break;
458
+ case 'phone_number':
459
+ pageData[key] = prop.phone_number;
460
+ break;
461
+ case 'created_by':
462
+ pageData[key] = prop.created_by.id;
463
+ break;
464
+ case 'last_edited_by':
465
+ pageData[key] = prop.last_edited_by.id;
466
+ break;
467
+ case 'people': {
468
+ const people = [];
469
+ for (const person of prop.people) {
470
+ people.push(person.id);
471
+ }
472
+ pageData[key] = people.join(',');
473
+ break;
474
+ }
475
+ case 'files': {
476
+ const files = [];
477
+ for (const file of prop.files) {
478
+ files.push(file.name);
479
+ }
480
+ pageData[key] = files.join(',');
481
+ break;
482
+ }
483
+ case 'checkbox':
484
+ pageData[key] = prop.checkbox;
485
+ break;
486
+ case 'unique_id':
487
+ pageData[key] = `${prop.unique_id.prefix}-${prop.unique_id.number}`;
488
+ break;
489
+ case 'title':
490
+ pageData[key] = prop.title[0].plain_text;
491
+ break;
492
+ case 'rich_text': {
493
+ const richTexts = [];
494
+ for (const richText of prop.rich_text) {
495
+ richTexts.push(richText.plain_text);
496
+ }
497
+ pageData[key] = richTexts.join(',');
498
+ break;
499
+ }
500
+ case 'status':
501
+ pageData[key] = prop.status === null ? '' : prop.status.name;
502
+ break;
503
+ default:
504
+ console.error(`${key}(type: ${prop.type}) is not supported`);
505
+ }
506
+ });
507
+ oneDepthJson.push(pageData);
508
+ }
509
+ return { oneDepthJson, relationJson };
510
+ };
511
+ exports.buildOneDepthJson = buildOneDepthJson;
512
+ const getDbTitle = (row) => {
513
+ if (row.title && row.title.length > 0) {
514
+ return row.title[0].plain_text;
515
+ }
516
+ return 'Untitled';
517
+ };
518
+ exports.getDbTitle = getDbTitle;
519
+ const getDataSourceTitle = (row) => {
520
+ // Check if it's a full data source response
521
+ if ((0, client_1.isFullDataSource)(row)) {
522
+ if (row.title && row.title.length > 0) {
523
+ return row.title[0].plain_text;
524
+ }
525
+ }
526
+ return 'Untitled';
527
+ };
528
+ exports.getDataSourceTitle = getDataSourceTitle;
529
+ const getPageTitle = (row) => {
530
+ let title = 'Untitled';
531
+ Object.entries(row.properties).find(([, prop]) => {
532
+ if (prop.type === 'title' && prop.title.length > 0) {
533
+ title = prop.title[0].plain_text;
534
+ return true;
535
+ }
536
+ });
537
+ return title;
538
+ };
539
+ exports.getPageTitle = getPageTitle;
540
+ const getBlockPlainText = (row) => {
541
+ try {
542
+ switch (row.type) {
543
+ case 'bookmark':
544
+ return row[row.type].url;
545
+ case 'breadcrumb':
546
+ return '';
547
+ case 'child_database':
548
+ return row[row.type].title;
549
+ case 'child_page':
550
+ return row[row.type].title;
551
+ case 'column_list':
552
+ return '';
553
+ case 'divider':
554
+ return '';
555
+ case 'embed':
556
+ return row[row.type].url;
557
+ case 'equation':
558
+ return row[row.type].expression;
559
+ case 'file':
560
+ case 'image':
561
+ if (row[row.type].type == 'file') {
562
+ return row[row.type].file.url;
563
+ }
564
+ else {
565
+ return row[row.type].external.url;
566
+ }
567
+ case 'link_preview':
568
+ return row[row.type].url;
569
+ case 'synced_block':
570
+ return '';
571
+ case 'table_of_contents':
572
+ return '';
573
+ case 'table':
574
+ return '';
575
+ case 'bulleted_list_item':
576
+ case 'callout':
577
+ case 'code':
578
+ case 'heading_1':
579
+ case 'heading_2':
580
+ case 'heading_3':
581
+ case 'numbered_list_item':
582
+ case 'paragraph':
583
+ case 'quote':
584
+ case 'to_do':
585
+ case 'toggle': {
586
+ let plainText = '';
587
+ if (row[row.type].rich_text.length > 0) {
588
+ plainText = row[row.type].rich_text[0].plain_text;
589
+ }
590
+ return plainText;
591
+ }
592
+ default:
593
+ return row[row.type];
594
+ }
595
+ }
596
+ catch (e) {
597
+ console.error(`${row.type} is not supported`);
598
+ console.error(e);
599
+ return '';
600
+ }
601
+ };
602
+ exports.getBlockPlainText = getBlockPlainText;
603
+ /**
604
+ * Helper to create rich text array from plain text string
605
+ */
606
+ const createRichText = (text) => {
607
+ return [
608
+ {
609
+ type: 'text',
610
+ text: {
611
+ content: text,
612
+ },
613
+ },
614
+ ];
615
+ };
616
+ /**
617
+ * Build block JSON from simple text-based flags
618
+ * Returns an array of block objects ready for Notion API
619
+ */
620
+ const buildBlocksFromTextFlags = (flags) => {
621
+ const blocks = [];
622
+ if (flags.text) {
623
+ blocks.push({
624
+ object: 'block',
625
+ type: 'paragraph',
626
+ paragraph: {
627
+ rich_text: createRichText(flags.text),
628
+ },
629
+ });
630
+ }
631
+ if (flags.heading1) {
632
+ blocks.push({
633
+ object: 'block',
634
+ type: 'heading_1',
635
+ heading_1: {
636
+ rich_text: createRichText(flags.heading1),
637
+ },
638
+ });
639
+ }
640
+ if (flags.heading2) {
641
+ blocks.push({
642
+ object: 'block',
643
+ type: 'heading_2',
644
+ heading_2: {
645
+ rich_text: createRichText(flags.heading2),
646
+ },
647
+ });
648
+ }
649
+ if (flags.heading3) {
650
+ blocks.push({
651
+ object: 'block',
652
+ type: 'heading_3',
653
+ heading_3: {
654
+ rich_text: createRichText(flags.heading3),
655
+ },
656
+ });
657
+ }
658
+ if (flags.bullet) {
659
+ blocks.push({
660
+ object: 'block',
661
+ type: 'bulleted_list_item',
662
+ bulleted_list_item: {
663
+ rich_text: createRichText(flags.bullet),
664
+ },
665
+ });
666
+ }
667
+ if (flags.numbered) {
668
+ blocks.push({
669
+ object: 'block',
670
+ type: 'numbered_list_item',
671
+ numbered_list_item: {
672
+ rich_text: createRichText(flags.numbered),
673
+ },
674
+ });
675
+ }
676
+ if (flags.todo) {
677
+ blocks.push({
678
+ object: 'block',
679
+ type: 'to_do',
680
+ to_do: {
681
+ rich_text: createRichText(flags.todo),
682
+ checked: false,
683
+ },
684
+ });
685
+ }
686
+ if (flags.toggle) {
687
+ blocks.push({
688
+ object: 'block',
689
+ type: 'toggle',
690
+ toggle: {
691
+ rich_text: createRichText(flags.toggle),
692
+ },
693
+ });
694
+ }
695
+ if (flags.code) {
696
+ blocks.push({
697
+ object: 'block',
698
+ type: 'code',
699
+ code: {
700
+ rich_text: createRichText(flags.code),
701
+ language: flags.language || 'plain text',
702
+ },
703
+ });
704
+ }
705
+ if (flags.quote) {
706
+ blocks.push({
707
+ object: 'block',
708
+ type: 'quote',
709
+ quote: {
710
+ rich_text: createRichText(flags.quote),
711
+ },
712
+ });
713
+ }
714
+ if (flags.callout) {
715
+ blocks.push({
716
+ object: 'block',
717
+ type: 'callout',
718
+ callout: {
719
+ rich_text: createRichText(flags.callout),
720
+ icon: {
721
+ type: 'emoji',
722
+ emoji: '💡',
723
+ },
724
+ },
725
+ });
726
+ }
727
+ return blocks;
728
+ };
729
+ exports.buildBlocksFromTextFlags = buildBlocksFromTextFlags;
730
+ /**
731
+ * Attempt to enrich a child_database block with its queryable data_source_id
732
+ *
733
+ * The Notion API returns child_database blocks without the database/data_source ID,
734
+ * making them unqueryable. This function attempts to resolve the block ID to a
735
+ * queryable data_source_id by trying to retrieve it as a data source.
736
+ *
737
+ * @param block The child_database block to enrich
738
+ * @returns The enriched block with data_source_id and database_id fields, or original block if resolution fails
739
+ */
740
+ const enrichChildDatabaseBlock = async (block) => {
741
+ // Only process child_database blocks
742
+ if (block.type !== 'child_database') {
743
+ return block;
744
+ }
745
+ try {
746
+ // Attempt to use the block ID as a data source ID
747
+ // In many cases, the child_database block ID IS the data source ID
748
+ const dataSource = await notion.retrieveDataSource(block.id);
749
+ // If successful, add the IDs to the block object
750
+ return {
751
+ ...block,
752
+ child_database: {
753
+ ...block.child_database,
754
+ // @ts-expect-error - Legacy type compatibility issue - Adding custom fields for discoverability
755
+ data_source_id: block.id,
756
+ database_id: dataSource.id,
757
+ },
758
+ };
759
+ }
760
+ catch {
761
+ // If retrieval fails, return the original block unchanged
762
+ // This is expected for some child_database blocks
763
+ return block;
764
+ }
765
+ };
766
+ exports.enrichChildDatabaseBlock = enrichChildDatabaseBlock;
767
+ /**
768
+ * Get all child_database blocks from a list of blocks and enrich them with queryable IDs
769
+ *
770
+ * @param blocks Array of blocks to filter and enrich
771
+ * @returns Array of enriched child_database blocks with title, block_id, data_source_id, and database_id
772
+ */
773
+ const getChildDatabasesWithIds = async (blocks) => {
774
+ const childDatabases = blocks.filter(block => (0, client_1.isFullBlock)(block) && block.type === 'child_database');
775
+ const enrichedDatabases = await Promise.all(childDatabases.map(async (block) => {
776
+ const enriched = await (0, exports.enrichChildDatabaseBlock)(block);
777
+ // Type guard to ensure we have a full block with child_database property
778
+ if (!(0, client_1.isFullBlock)(enriched) || enriched.type !== 'child_database') {
779
+ return {
780
+ block_id: enriched.id,
781
+ title: 'Untitled',
782
+ data_source_id: null,
783
+ database_id: null,
784
+ };
785
+ }
786
+ return {
787
+ block_id: enriched.id,
788
+ title: enriched.child_database.title,
789
+ // @ts-expect-error - Legacy type compatibility issue - Custom fields added by enrichChildDatabaseBlock
790
+ data_source_id: enriched.child_database.data_source_id || null,
791
+ // @ts-expect-error - Legacy type compatibility issue
792
+ database_id: enriched.child_database.database_id || null,
793
+ };
794
+ }));
795
+ return enrichedDatabases;
796
+ };
797
+ exports.getChildDatabasesWithIds = getChildDatabasesWithIds;
798
+ /**
799
+ * Build block update content from simple text flags
800
+ * Returns an object with the block type properties for updating
801
+ */
802
+ const buildBlockUpdateFromTextFlags = (blockType, flags) => {
803
+ // For updates, we need to know the block type and provide the appropriate content
804
+ // The text flags can update any compatible block type
805
+ if (flags.text) {
806
+ return {
807
+ paragraph: {
808
+ rich_text: createRichText(flags.text),
809
+ },
810
+ };
811
+ }
812
+ if (flags.heading1) {
813
+ return {
814
+ heading_1: {
815
+ rich_text: createRichText(flags.heading1),
816
+ },
817
+ };
818
+ }
819
+ if (flags.heading2) {
820
+ return {
821
+ heading_2: {
822
+ rich_text: createRichText(flags.heading2),
823
+ },
824
+ };
825
+ }
826
+ if (flags.heading3) {
827
+ return {
828
+ heading_3: {
829
+ rich_text: createRichText(flags.heading3),
830
+ },
831
+ };
832
+ }
833
+ if (flags.bullet) {
834
+ return {
835
+ bulleted_list_item: {
836
+ rich_text: createRichText(flags.bullet),
837
+ },
838
+ };
839
+ }
840
+ if (flags.numbered) {
841
+ return {
842
+ numbered_list_item: {
843
+ rich_text: createRichText(flags.numbered),
844
+ },
845
+ };
846
+ }
847
+ if (flags.todo) {
848
+ return {
849
+ to_do: {
850
+ rich_text: createRichText(flags.todo),
851
+ },
852
+ };
853
+ }
854
+ if (flags.toggle) {
855
+ return {
856
+ toggle: {
857
+ rich_text: createRichText(flags.toggle),
858
+ },
859
+ };
860
+ }
861
+ if (flags.code) {
862
+ return {
863
+ code: {
864
+ rich_text: createRichText(flags.code),
865
+ language: flags.language || 'plain text',
866
+ },
867
+ };
868
+ }
869
+ if (flags.quote) {
870
+ return {
871
+ quote: {
872
+ rich_text: createRichText(flags.quote),
873
+ },
874
+ };
875
+ }
876
+ if (flags.callout) {
877
+ return {
878
+ callout: {
879
+ rich_text: createRichText(flags.callout),
880
+ },
881
+ };
882
+ }
883
+ return null;
884
+ };
885
+ exports.buildBlockUpdateFromTextFlags = buildBlockUpdateFromTextFlags;