gatsby-source-notion-churnotion 1.1.28 → 1.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,6 +6,21 @@ This plugin recursively collects categories from a single Notion database, which
6
6
 
7
7
  If you're considering Notion as your CMS for Gatsby, this plugin could be a great choice as it supports recursive category collection.
8
8
 
9
+ ## What's New in v1.1.29
10
+
11
+ - **Added support for more Notion block types**:
12
+ - bookmark, breadcrumb, callout, code, column, column_list, divider, embed, equation, file, link_preview, pdf, table, table_of_contents, toggle, to_do, video, audio
13
+ - **Improved performance**:
14
+ - Added parallel processing for Notion API requests with concurrency limits
15
+ - Implemented caching to reduce duplicate API calls
16
+ - Added batch processing for large datasets
17
+ - Added timeout handling for long-running operations
18
+ - **Code refactoring**:
19
+ - Modular block processor architecture
20
+ - Better error handling
21
+ - Improved type safety
22
+ - Fixed ES Module import issue with p-limit
23
+
9
24
  ## Install
10
25
 
11
26
  ```shell
@@ -64,7 +79,7 @@ When the development server is running, `gatsby-source-notion-churnotion` will f
64
79
 
65
80
  ### Explore in GraphQL
66
81
 
67
- Once the data is fetched, go to http://localhost:8000/__graphql, where youll find new nodes such as `Churnotion`, `NBook`, `NCategory`, and `NTag` as shown below:
82
+ Once the data is fetched, go to http://localhost:8000/__graphql, where you'll find new nodes such as `Churnotion`, `NBook`, `NCategory`, and `NTag` as shown below:
68
83
 
69
84
  ![alt text](readme2.png)
70
85
 
@@ -6,237 +6,122 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getPages = void 0;
7
7
  const crypto_1 = __importDefault(require("crypto"));
8
8
  const constants_1 = require("../constants");
9
- const fetchData_1 = require("../util/fetchData");
10
9
  const processor_1 = require("../util/processor");
11
10
  const slugify_1 = require("../util/slugify");
12
- const bookCategoryMap_1 = __importDefault(require("../util/bookCategoryMap"));
13
11
  const formatDate_1 = require("../util/formatDate");
12
+ const service_1 = require("./service");
13
+ const timeLimit_1 = require("../util/timeLimit");
14
+ // 최대 동시 요청 수 설정
15
+ const MAX_CONCURRENT_REQUESTS = 5;
14
16
  const getPages = async ({ databaseId, reporter, getCache, actions, createNode, createNodeId, createParentChildLink, getNode, cache, }) => {
17
+ // Notion Service 초기화
18
+ const notionService = new service_1.NotionService({
19
+ reporter,
20
+ parallelLimit: MAX_CONCURRENT_REQUESTS,
21
+ enableCaching: true,
22
+ });
23
+ // 태그 매핑을 위한 객체
24
+ const tagMap = {};
15
25
  /**
16
26
  * 데이터베이스 내에 페이지들을 읽어서 재귀적으로 추가하는 서브 메서드드
17
27
  * @param databaseId 데이터베이스 아이디
18
28
  * @param parentCategoryId 부모 데이터베이스 아이디
19
29
  */
20
- const processDatabase = async (databaseId, parentCategoryId = null, categoryPath = [], tagMap = {}, parentCategoryUrl = ``) => {
30
+ const processDatabase = async (databaseId, parentCategoryId = null, categoryPath = [], parentCategoryUrl = ``) => {
21
31
  let hasMore = true;
22
32
  try {
33
+ // 동시에 처리될 페이지 목록
34
+ const pagesToProcess = [];
23
35
  while (hasMore) {
24
- const databaseUrl = `databases/${databaseId}/query`;
25
- const body = {};
26
- const result = await (0, fetchData_1.fetchPostWithRetry)(databaseUrl, body);
36
+ // 데이터베이스 쿼리
37
+ const result = await notionService.queryDatabase(databaseId);
38
+ hasMore = false; // Notion API가 페이지네이션을 완전히 지원하지 않으므로 일단 한 번만 처리
27
39
  if (result?.results?.length) {
28
40
  reporter.info(`[SUCCESS] total pages > ${result.results.length}`);
29
- }
30
- for (const page of result.results) {
31
- const pageUrl = `blocks/${page.id}/children?page_size=100`;
32
- // 페이지 데이터
33
- const pageData = await (0, fetchData_1.fetchGetWithRetry)(pageUrl);
34
- if (pageData.results[0].type === `child_database`) {
35
- const categoryJsonData = pageData.results[0];
36
- const title = categoryJsonData.child_database?.title || `Unnamed Category`;
37
- const slug = (0, slugify_1.slugify)(title) || `no-title-${categoryJsonData.id}`;
38
- if (!title) {
39
- reporter.warn(`[WARNING] Category without a title detected: ${categoryJsonData.id}`);
40
- }
41
- const nodeId = createNodeId(`${categoryJsonData.id}-category`);
42
- const categoryUrl = `${parentCategoryUrl}/${slug}`;
43
- const categoryNode = {
44
- id: nodeId,
45
- category_name: title,
46
- parent: parentCategoryId,
47
- slug: slug,
48
- children: [],
49
- internal: {
50
- type: constants_1.NODE_TYPE.Category,
51
- contentDigest: crypto_1.default
52
- .createHash(`md5`)
53
- .update(JSON.stringify(categoryJsonData))
54
- .digest(`hex`),
55
- },
56
- url: `${constants_1.COMMON_URI}/${constants_1.CATEGORY_URI}${categoryUrl}`,
57
- books: [],
58
- };
59
- await createNode(categoryNode);
60
- const bookRelations = page.properties?.book?.relation || null;
61
- if (bookRelations) {
62
- bookRelations.forEach((relation) => {
63
- const bookId = relation.id;
64
- const bookNodeId = createNodeId(`${bookId}-book`);
65
- const bookNode = getNode(bookNodeId);
66
- if (bookNode) {
67
- createParentChildLink({
68
- parent: categoryNode,
69
- child: bookNode,
70
- });
71
- const updatedBookNode = {
72
- ...bookNode,
73
- book_category: categoryNode.id,
74
- internal: {
75
- type: bookNode.internal.type,
76
- contentDigest: crypto_1.default
77
- .createHash(`md5`)
78
- .update(JSON.stringify(bookNode))
79
- .digest(`hex`),
80
- },
81
- };
82
- createNode(updatedBookNode);
83
- reporter.info(`[SUCCESS] Linked Category-Book: ${categoryNode.category_name} -> child: ${bookNode.book_name}`);
84
- }
85
- });
86
- }
87
- if (parentCategoryId && categoryNode) {
88
- const parentNode = getNode(parentCategoryId); // Gatsby에서 노드를 검색
89
- if (parentNode) {
90
- createParentChildLink({
91
- parent: parentNode,
92
- child: categoryNode,
93
- });
94
- reporter.info(`[SUCCESS] Linked parent: ${parentNode.category_name} -> child: ${categoryNode.category_name}`);
95
- }
96
- else {
97
- reporter.warn(`[WARNING] Parent node not found for ID: ${parentCategoryId}`);
98
- }
99
- }
100
- const newCategoryPath = [...categoryPath, categoryNode];
101
- await processDatabase(categoryJsonData.id, nodeId, newCategoryPath, tagMap, categoryUrl);
102
- }
103
- else {
104
- // 페이지인 경우
105
- const title = page.properties?.[`이름`]?.title?.[0]?.plain_text || `Unnamed`;
106
- const slug = (0, slugify_1.slugify)(page.properties?.[`slug`]?.rich_text?.[0]?.plain_text ||
107
- crypto_1.default
108
- .createHash(`md5`)
109
- .update(JSON.stringify(title))
110
- .digest(`hex`));
111
- if (!page.properties?.[`이름`]?.title?.[0]?.plain_text) {
112
- reporter.warn(`[WARNING] Category without a title detected: ${page.id}`);
113
- }
114
- const nodeId = createNodeId(`${page.id}-page`);
115
- // Tag 노드 만들기
116
- const tagIds = [];
117
- if (page.properties.tags && page.properties.tags.multi_select) {
118
- page.properties.tags.multi_select.forEach((tagData) => {
119
- if (tagMap[tagData.name]) {
120
- // 이미 존재하는 태그라면 tagMap에서 가져오기
121
- const existingTagId = tagMap[tagData.name];
122
- tagIds.push(existingTagId); // 기존 태그 ID 추가
123
- reporter.info(`[INFO] Reusing existing tag: ${tagData.name}`);
124
- }
125
- else {
126
- // 새로운 태그 생성
127
- const tagNodeId = createNodeId(`${tagData.id}-tag`);
128
- tagMap[tagData.name] = tagNodeId; // tagMap에 저장
129
- tagIds.push(tagNodeId); // 새로운 태그 ID 추가
130
- const slug = (0, slugify_1.slugify)(tagData.name) || `no-tag-${tagNodeId}`;
131
- // 태그 노드 생성
132
- const tagNode = {
133
- id: tagNodeId,
134
- tag_name: tagData.name,
135
- slug: slug,
136
- color: tagData.color,
137
- children: [],
138
- internal: {
139
- type: constants_1.NODE_TYPE.Tag,
140
- contentDigest: crypto_1.default
141
- .createHash(`md5`)
142
- .update(JSON.stringify(tagData))
143
- .digest(`hex`),
144
- },
145
- url: `${constants_1.COMMON_URI}/${constants_1.TAG_URI}/${slug}`,
146
- churnotions: [],
147
- parent: null,
148
- };
149
- createNode(tagNode);
150
- reporter.info(`[SUCCESS] Created new tag: ${tagData.name}`);
151
- }
152
- });
153
- }
154
- const bookId = page.properties?.book?.relation?.[0]?.id || null;
155
- const bookNodeId = createNodeId(`${bookId}-book`);
156
- const bookNode = getNode(bookNodeId);
157
- const [imageNode, tableOfContents, updatedBlocks, rawText] = await (0, processor_1.processor)(pageData.results, actions, getCache, createNodeId, reporter, cache);
158
- const postNode = {
159
- id: nodeId,
160
- category: parentCategoryId,
161
- book: bookNode?.id,
162
- book_index: page.properties?.bookIndex?.number || 0,
163
- title: title,
164
- content: updatedBlocks,
165
- create_date: (0, formatDate_1.useFormatDate)(page.created_time),
166
- update_date: (0, formatDate_1.useFormatDate)(page.last_edited_time),
167
- version: page.properties?.version?.number || null,
168
- description: page.properties?.description?.rich_text?.[0]?.plain_text ||
169
- rawText.substring(0, 400),
170
- slug: slug,
171
- category_list: categoryPath,
172
- children: [],
173
- tableOfContents,
174
- internal: {
175
- type: constants_1.NODE_TYPE.Post,
176
- contentDigest: crypto_1.default
177
- .createHash(`md5`)
178
- .update(JSON.stringify(nodeId))
179
- .digest(`hex`),
180
- },
181
- tags: tagIds,
182
- parent: null,
183
- url: `${constants_1.COMMON_URI}/${constants_1.POST_URI}${parentCategoryUrl}/${slug}`,
184
- thumbnail: imageNode,
185
- rawText,
186
- };
187
- await createNode(postNode);
188
- if (bookNode) {
189
- createParentChildLink({
190
- parent: bookNode,
191
- child: postNode,
192
- });
193
- reporter.info(`[SUCCESS] Linked book: ${bookNode.book_name} -> page: ${postNode.title}`);
194
- }
195
- // tag와 post 부모-자식 관계 설정
196
- tagIds.forEach((tagId) => {
197
- const tagNode = getNode(tagId);
198
- if (tagNode) {
199
- createParentChildLink({
200
- parent: tagNode,
201
- child: postNode,
202
- });
203
- reporter.info(`[SUCCESS] Linked tag: ${tagNode.tag_name} -> page: ${postNode.title}`);
204
- }
205
- else {
206
- reporter.warn(`[WARNING] Tag node not found for ID: ${tagId}`);
207
- }
208
- });
209
- // category와 post 부모-자식 관계 설정
210
- if (parentCategoryId && postNode) {
211
- const parentNode = getNode(parentCategoryId); // Gatsby에서 노드를 검색
212
- if (parentNode) {
213
- createParentChildLink({
214
- parent: parentNode,
215
- child: postNode,
216
- });
217
- reporter.info(`[SUCCESS] Linked parent: ${parentNode.category_name} -> child: ${postNode.title}`);
218
- }
219
- else {
220
- reporter.warn(`[WARNING] Parent node not found for ID: ${parentCategoryId}`);
41
+ // 페이지 ID 목록 수집
42
+ const pageIds = result.results.map((page) => page.id);
43
+ // 페이지 블록들을 병렬로 가져오기 - 최대 50개씩 배치 처리
44
+ for (let i = 0; i < pageIds.length; i += 50) {
45
+ const batch = pageIds.slice(i, i + 50);
46
+ reporter.info(`[BATCH] Processing pages ${i + 1} to ${i + batch.length} of ${pageIds.length}`);
47
+ const batchBlocks = await notionService.getMultiplePagesBlocks(batch);
48
+ // 페이지 데이터와 블록 결합
49
+ for (const pageId of batch) {
50
+ const page = result.results.find((p) => p.id === pageId);
51
+ if (page) {
52
+ const pageData = {
53
+ page,
54
+ blocks: batchBlocks[pageId] || [],
55
+ };
56
+ pagesToProcess.push(pageData);
221
57
  }
222
58
  }
223
59
  }
224
60
  }
225
- hasMore = result.has_more;
226
61
  }
62
+ // 모든 페이지 병렬 처리
63
+ await Promise.all(pagesToProcess.map(async ({ page, blocks }) => {
64
+ try {
65
+ // Timeout 설정으로 너무 오래 걸리는 페이지는 건너뛰기
66
+ await (0, timeLimit_1.timeLimit)(processPageData(page, blocks, parentCategoryId, categoryPath, tagMap, parentCategoryUrl), 30000, // 30초 제한
67
+ `Processing page ${page.id} timed out after 30 seconds`);
68
+ }
69
+ catch (error) {
70
+ reporter.warn(`[WARNING] Error processing page ${page.id}: ${error}`);
71
+ }
72
+ }));
227
73
  }
228
74
  catch (error) {
229
- reporter.error(`[ERROR] fetching page`);
230
- hasMore = false;
75
+ reporter.error(`[ERROR] Processing database ${databaseId} failed: ${error}`);
231
76
  }
232
77
  };
233
- await processDatabase(databaseId);
234
- // Category - Book Relation Update
235
- for (const [categoryId, bookIds] of bookCategoryMap_1.default.entries()) {
236
- const categoryNode = getNode(categoryId);
237
- if (categoryNode) {
238
- for (const bookId of bookIds) {
239
- const bookNode = getNode(bookId);
78
+ /**
79
+ * 페이지 데이터 처리 메서드
80
+ */
81
+ const processPageData = async (page, pageBlocks, parentCategoryId, categoryPath, tagMap, parentCategoryUrl) => {
82
+ // 번째 블록이 child_database인지 확인
83
+ if (pageBlocks?.[0]?.type === `child_database`) {
84
+ await processCategory(page, pageBlocks, parentCategoryId, categoryPath, tagMap, parentCategoryUrl);
85
+ }
86
+ else {
87
+ await processPost(page, pageBlocks, parentCategoryId, categoryPath, tagMap, parentCategoryUrl);
88
+ }
89
+ };
90
+ /**
91
+ * 카테고리 처리 메서드
92
+ */
93
+ const processCategory = async (page, pageBlocks, parentCategoryId, categoryPath, tagMap, parentCategoryUrl) => {
94
+ const categoryJsonData = pageBlocks[0];
95
+ const title = categoryJsonData.child_database?.title || `Unnamed Category`;
96
+ const slug = (0, slugify_1.slugify)(title) || `no-title-${categoryJsonData.id}`;
97
+ if (!title) {
98
+ reporter.warn(`[WARNING] Category without a title detected: ${categoryJsonData.id}`);
99
+ }
100
+ const nodeId = createNodeId(`${categoryJsonData.id}-category`);
101
+ const categoryUrl = `${parentCategoryUrl}/${slug}`;
102
+ const categoryNode = {
103
+ id: nodeId,
104
+ category_name: title,
105
+ parent: parentCategoryId,
106
+ slug: slug,
107
+ children: [],
108
+ internal: {
109
+ type: constants_1.NODE_TYPE.Category,
110
+ contentDigest: crypto_1.default
111
+ .createHash(`md5`)
112
+ .update(JSON.stringify(categoryJsonData))
113
+ .digest(`hex`),
114
+ },
115
+ url: `${constants_1.COMMON_URI}/${constants_1.CATEGORY_URI}${categoryUrl}`,
116
+ books: [],
117
+ };
118
+ await createNode(categoryNode);
119
+ const bookRelations = page.properties?.book?.relation || null;
120
+ if (bookRelations) {
121
+ bookRelations.forEach((relation) => {
122
+ const bookId = relation.id;
123
+ const bookNodeId = createNodeId(`${bookId}-book`);
124
+ const bookNode = getNode(bookNodeId);
240
125
  if (bookNode) {
241
126
  createParentChildLink({
242
127
  parent: categoryNode,
@@ -254,16 +139,153 @@ const getPages = async ({ databaseId, reporter, getCache, actions, createNode, c
254
139
  },
255
140
  };
256
141
  createNode(updatedBookNode);
257
- reporter.info(`[SUCCESS] Linked Book to Category: ${bookNode.book_name} -> ${categoryNode.category_name}`);
142
+ reporter.info(`[SUCCESS] Linked Category-Book: ${categoryNode.category_name} -> child: ${bookNode.book_name}`);
143
+ }
144
+ });
145
+ }
146
+ if (parentCategoryId && categoryNode) {
147
+ const parentNode = getNode(parentCategoryId);
148
+ if (parentNode) {
149
+ createParentChildLink({
150
+ parent: parentNode,
151
+ child: categoryNode,
152
+ });
153
+ reporter.info(`[SUCCESS] Linked parent: ${parentNode.category_name} -> child: ${categoryNode.category_name}`);
154
+ }
155
+ else {
156
+ reporter.warn(`[WARNING] Parent node not found for ID: ${parentCategoryId}`);
157
+ }
158
+ }
159
+ const newCategoryPath = [...categoryPath, categoryNode];
160
+ await processDatabase(categoryJsonData.id, nodeId, newCategoryPath, categoryUrl);
161
+ };
162
+ /**
163
+ * 포스트 처리 메서드
164
+ */
165
+ const processPost = async (page, pageBlocks, parentCategoryId, categoryPath, tagMap, parentCategoryUrl) => {
166
+ const title = page.properties?.[`이름`]?.title?.[0]?.plain_text || `Unnamed`;
167
+ const slug = (0, slugify_1.slugify)(page.properties?.[`slug`]?.rich_text?.[0]?.plain_text ||
168
+ crypto_1.default.createHash(`md5`).update(JSON.stringify(title)).digest(`hex`));
169
+ if (!page.properties?.[`이름`]?.title?.[0]?.plain_text) {
170
+ reporter.warn(`[WARNING] Post without a title detected: ${page.id}`);
171
+ }
172
+ const nodeId = createNodeId(`${page.id}-page`);
173
+ // Tag 노드 만들기
174
+ const tagIds = [];
175
+ if (page.properties.tags && page.properties.tags.multi_select) {
176
+ page.properties.tags.multi_select.forEach((tagData) => {
177
+ if (tagMap[tagData.name]) {
178
+ // 이미 존재하는 태그라면 tagMap에서 가져오기
179
+ const existingTagId = tagMap[tagData.name];
180
+ tagIds.push(existingTagId); // 기존 태그 ID 추가
181
+ reporter.info(`[INFO] Reusing existing tag: ${tagData.name}`);
258
182
  }
259
183
  else {
260
- reporter.warn(`[WARNING] Book node not found: ${bookId}`);
184
+ // 새로운 태그 생성
185
+ const tagNodeId = createNodeId(`${tagData.id}-tag`);
186
+ tagMap[tagData.name] = tagNodeId; // tagMap에 저장
187
+ tagIds.push(tagNodeId); // 새로운 태그 ID 추가
188
+ const slug = (0, slugify_1.slugify)(tagData.name) || `no-tag-${tagNodeId}`;
189
+ // 태그 노드 생성
190
+ const tagNode = {
191
+ id: tagNodeId,
192
+ tag_name: tagData.name,
193
+ slug: slug,
194
+ color: tagData.color,
195
+ children: [],
196
+ internal: {
197
+ type: constants_1.NODE_TYPE.Tag,
198
+ contentDigest: crypto_1.default
199
+ .createHash(`md5`)
200
+ .update(JSON.stringify(tagData))
201
+ .digest(`hex`),
202
+ },
203
+ url: `${constants_1.COMMON_URI}/${constants_1.TAG_URI}/${slug}`,
204
+ churnotions: [],
205
+ parent: null,
206
+ };
207
+ createNode(tagNode);
208
+ reporter.info(`[SUCCESS] Created new tag: ${tagData.name}`);
261
209
  }
210
+ });
211
+ }
212
+ const bookId = page.properties?.book?.relation?.[0]?.id || null;
213
+ const bookNodeId = createNodeId(`${bookId}-book`);
214
+ const bookNode = getNode(bookNodeId);
215
+ const [imageNode, tableOfContents, updatedBlocks, rawText] = await (0, processor_1.processor)(pageBlocks, actions, getCache, createNodeId, reporter, cache);
216
+ const postNode = {
217
+ id: nodeId,
218
+ category: parentCategoryId,
219
+ book: bookNode?.id,
220
+ book_index: page.properties?.bookIndex?.number || 0,
221
+ title: title,
222
+ content: updatedBlocks,
223
+ create_date: (0, formatDate_1.useFormatDate)(page.created_time),
224
+ update_date: (0, formatDate_1.useFormatDate)(page.last_edited_time),
225
+ version: page.properties?.version?.number || null,
226
+ description: page.properties?.description?.rich_text?.[0]?.plain_text ||
227
+ rawText.substring(0, 400),
228
+ slug: slug,
229
+ category_list: categoryPath,
230
+ children: [],
231
+ tags: tagIds,
232
+ tableOfContents,
233
+ internal: {
234
+ type: constants_1.NODE_TYPE.Post,
235
+ contentDigest: crypto_1.default
236
+ .createHash(`md5`)
237
+ .update(JSON.stringify(nodeId))
238
+ .digest(`hex`),
239
+ },
240
+ url: `${constants_1.COMMON_URI}/${constants_1.POST_URI}/${slug}`,
241
+ thumbnail: imageNode,
242
+ parent: parentCategoryId,
243
+ };
244
+ await createNode(postNode);
245
+ if (parentCategoryId) {
246
+ const parentNode = getNode(parentCategoryId);
247
+ if (parentNode) {
248
+ createParentChildLink({
249
+ parent: parentNode,
250
+ child: postNode,
251
+ });
252
+ reporter.info(`[SUCCESS] Linked parent: ${parentNode.category_name} -> child: ${postNode.title}`);
262
253
  }
263
254
  }
264
- else {
265
- reporter.warn(`[WARNING] Category node not found: ${categoryId}`);
255
+ // 태그와 포스트 연결
256
+ tagIds.forEach((tagId) => {
257
+ const tagNode = getNode(tagId);
258
+ if (tagNode) {
259
+ const updatedTagNode = {
260
+ ...tagNode,
261
+ churnotions: [...(tagNode.churnotions || []), nodeId],
262
+ internal: {
263
+ type: tagNode.internal.type,
264
+ contentDigest: crypto_1.default
265
+ .createHash(`md5`)
266
+ .update(JSON.stringify({
267
+ ...tagNode,
268
+ churnotions: [...(tagNode.churnotions || []), nodeId],
269
+ }))
270
+ .digest(`hex`),
271
+ },
272
+ };
273
+ createNode(updatedTagNode);
274
+ reporter.info(`[SUCCESS] Added post to tag: ${tagNode.tag_name} -> ${postNode.title}`);
275
+ }
276
+ });
277
+ // 책과 포스트 연결
278
+ if (bookNode && postNode) {
279
+ createParentChildLink({
280
+ parent: bookNode,
281
+ child: postNode,
282
+ });
283
+ reporter.info(`[SUCCESS] Linked Book-Post: ${bookNode.book_name} -> child: ${postNode.title}`);
266
284
  }
267
- }
285
+ };
286
+ // 초기 데이터베이스 처리 시작
287
+ await processDatabase(databaseId);
288
+ // 캐시 정리
289
+ notionService.clearCache();
268
290
  };
269
291
  exports.getPages = getPages;
@@ -0,0 +1 @@
1
+ export * from "./notionService";
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./notionService"), exports);
@@ -0,0 +1,39 @@
1
+ import { Reporter } from "gatsby";
2
+ import { BaseContentBlock } from "notion-types";
3
+ export interface NotionServiceOptions {
4
+ reporter: Reporter;
5
+ parallelLimit?: number;
6
+ enableCaching?: boolean;
7
+ }
8
+ export declare class NotionService {
9
+ private reporter;
10
+ private parallelLimit;
11
+ private enableCaching;
12
+ private cache;
13
+ private limiter;
14
+ constructor(options: NotionServiceOptions);
15
+ private initLimiter;
16
+ private createSimpleLimiter;
17
+ /**
18
+ * 데이터베이스 쿼리
19
+ */
20
+ queryDatabase(databaseId: string, body?: any): Promise<any>;
21
+ /**
22
+ * 페이지의 자식 블록 가져오기
23
+ */
24
+ getPageBlocks(pageId: string): Promise<BaseContentBlock[]>;
25
+ /**
26
+ * 여러 페이지의 블록 병렬 처리
27
+ */
28
+ getMultiplePagesBlocks(pageIds: string[]): Promise<{
29
+ [id: string]: BaseContentBlock[];
30
+ }>;
31
+ /**
32
+ * 캐시 초기화
33
+ */
34
+ clearCache(): void;
35
+ /**
36
+ * 병렬 처리 제한 설정
37
+ */
38
+ setParallelLimit(limit: number): Promise<void>;
39
+ }