katanakit-js 6.2.0 → 6.6.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 (116) hide show
  1. package/README.md +11 -3
  2. package/dist/adapters/better-auth/better-auth.service.d.ts +83 -0
  3. package/dist/adapters/better-auth/better-auth.service.d.ts.map +1 -0
  4. package/dist/adapters/better-auth/better-auth.service.js +110 -0
  5. package/dist/adapters/better-auth/better-auth.service.js.map +1 -0
  6. package/dist/adapters/better-auth/client.d.ts +51 -0
  7. package/dist/adapters/better-auth/client.d.ts.map +1 -0
  8. package/dist/adapters/better-auth/client.js +67 -0
  9. package/dist/adapters/better-auth/client.js.map +1 -0
  10. package/dist/adapters/better-auth/index.d.ts +3 -0
  11. package/dist/adapters/better-auth/index.d.ts.map +1 -0
  12. package/dist/adapters/better-auth/index.js +3 -0
  13. package/dist/adapters/better-auth/index.js.map +1 -0
  14. package/dist/adapters/express/server.d.ts +133 -1
  15. package/dist/adapters/express/server.d.ts.map +1 -1
  16. package/dist/adapters/express/server.js +199 -97
  17. package/dist/adapters/express/server.js.map +1 -1
  18. package/dist/adapters/index.d.ts +2 -0
  19. package/dist/adapters/index.d.ts.map +1 -1
  20. package/dist/adapters/index.js +2 -0
  21. package/dist/adapters/index.js.map +1 -1
  22. package/dist/adapters/insforge/insforge.service.d.ts +139 -4
  23. package/dist/adapters/insforge/insforge.service.d.ts.map +1 -1
  24. package/dist/adapters/insforge/insforge.service.js +383 -213
  25. package/dist/adapters/insforge/insforge.service.js.map +1 -1
  26. package/dist/adapters/notion/notion.service.d.ts +130 -144
  27. package/dist/adapters/notion/notion.service.d.ts.map +1 -1
  28. package/dist/adapters/notion/notion.service.js +330 -341
  29. package/dist/adapters/notion/notion.service.js.map +1 -1
  30. package/dist/adapters/photoswipe/index.d.ts +2 -0
  31. package/dist/adapters/photoswipe/index.d.ts.map +1 -0
  32. package/dist/adapters/photoswipe/index.js +2 -0
  33. package/dist/adapters/photoswipe/index.js.map +1 -0
  34. package/dist/adapters/photoswipe/photoswipe.service.d.ts +99 -0
  35. package/dist/adapters/photoswipe/photoswipe.service.d.ts.map +1 -0
  36. package/dist/adapters/photoswipe/photoswipe.service.js +150 -0
  37. package/dist/adapters/photoswipe/photoswipe.service.js.map +1 -0
  38. package/dist/adapters/telegram/telegram.service.d.ts +82 -13
  39. package/dist/adapters/telegram/telegram.service.d.ts.map +1 -1
  40. package/dist/adapters/telegram/telegram.service.js +133 -55
  41. package/dist/adapters/telegram/telegram.service.js.map +1 -1
  42. package/dist/adapters/wordpress/wordpress.service.d.ts +181 -110
  43. package/dist/adapters/wordpress/wordpress.service.d.ts.map +1 -1
  44. package/dist/adapters/wordpress/wordpress.service.js +556 -465
  45. package/dist/adapters/wordpress/wordpress.service.js.map +1 -1
  46. package/dist/config/seo.service.d.ts +1 -1
  47. package/dist/config/seo.service.d.ts.map +1 -1
  48. package/dist/config/seo.service.js +1 -1
  49. package/dist/config/seo.service.js.map +1 -1
  50. package/dist/core/services/access.service.d.ts +167 -4
  51. package/dist/core/services/access.service.d.ts.map +1 -1
  52. package/dist/core/services/access.service.js +241 -31
  53. package/dist/core/services/access.service.js.map +1 -1
  54. package/dist/core/services/agent.service.d.ts +182 -27
  55. package/dist/core/services/agent.service.d.ts.map +1 -1
  56. package/dist/core/services/agent.service.js +296 -164
  57. package/dist/core/services/agent.service.js.map +1 -1
  58. package/dist/core/services/assistant.service.d.ts +96 -5
  59. package/dist/core/services/assistant.service.d.ts.map +1 -1
  60. package/dist/core/services/assistant.service.js +171 -66
  61. package/dist/core/services/assistant.service.js.map +1 -1
  62. package/dist/core/services/dates.service.d.ts +183 -11
  63. package/dist/core/services/dates.service.d.ts.map +1 -1
  64. package/dist/core/services/dates.service.js +256 -57
  65. package/dist/core/services/dates.service.js.map +1 -1
  66. package/dist/core/services/http.service.d.ts +172 -133
  67. package/dist/core/services/http.service.d.ts.map +1 -1
  68. package/dist/core/services/http.service.js +367 -310
  69. package/dist/core/services/http.service.js.map +1 -1
  70. package/dist/core/services/logger.service.d.ts +96 -34
  71. package/dist/core/services/logger.service.d.ts.map +1 -1
  72. package/dist/core/services/logger.service.js +128 -41
  73. package/dist/core/services/logger.service.js.map +1 -1
  74. package/dist/core/services/query.service.d.ts +101 -0
  75. package/dist/core/services/query.service.d.ts.map +1 -1
  76. package/dist/core/services/query.service.js +131 -14
  77. package/dist/core/services/query.service.js.map +1 -1
  78. package/dist/core/services/utils.service.d.ts +286 -131
  79. package/dist/core/services/utils.service.d.ts.map +1 -1
  80. package/dist/core/services/utils.service.js +417 -227
  81. package/dist/core/services/utils.service.js.map +1 -1
  82. package/dist/core/services/validation.service.d.ts +48 -3
  83. package/dist/core/services/validation.service.d.ts.map +1 -1
  84. package/dist/core/services/validation.service.js +75 -23
  85. package/dist/core/services/validation.service.js.map +1 -1
  86. package/dist/infrastructure/decorators/cache.decorator.d.ts +53 -0
  87. package/dist/infrastructure/decorators/cache.decorator.d.ts.map +1 -0
  88. package/dist/infrastructure/decorators/cache.decorator.js +47 -0
  89. package/dist/infrastructure/decorators/cache.decorator.js.map +1 -0
  90. package/dist/infrastructure/decorators/index.d.ts +4 -0
  91. package/dist/infrastructure/decorators/index.d.ts.map +1 -0
  92. package/dist/infrastructure/decorators/index.js +4 -0
  93. package/dist/infrastructure/decorators/index.js.map +1 -0
  94. package/dist/infrastructure/decorators/logger.decorator.d.ts +38 -0
  95. package/dist/infrastructure/decorators/logger.decorator.d.ts.map +1 -0
  96. package/dist/infrastructure/decorators/logger.decorator.js +66 -0
  97. package/dist/infrastructure/decorators/logger.decorator.js.map +1 -0
  98. package/dist/infrastructure/decorators/retry.decorator.d.ts +37 -0
  99. package/dist/infrastructure/decorators/retry.decorator.d.ts.map +1 -0
  100. package/dist/infrastructure/decorators/retry.decorator.js +54 -0
  101. package/dist/infrastructure/decorators/retry.decorator.js.map +1 -0
  102. package/dist/infrastructure/index.d.ts +1 -0
  103. package/dist/infrastructure/index.d.ts.map +1 -1
  104. package/dist/infrastructure/index.js +1 -0
  105. package/dist/infrastructure/index.js.map +1 -1
  106. package/dist/styles.css +2 -0
  107. package/package.json +49 -14
  108. package/scss/_flags.scss +179 -0
  109. package/scss/_functions.scss +168 -0
  110. package/scss/_mixins.scss +658 -0
  111. package/scss/_reset.scss +275 -0
  112. package/scss/_utilities.scss +449 -0
  113. package/scss/_variables.scss +539 -0
  114. package/scss/components/_index.scss +50 -0
  115. package/scss/demo.scss +12 -0
  116. package/scss/main.scss +56 -0
@@ -6,83 +6,324 @@ import { NotionBlockListSchema, NotionBlockResponseSchema, NotionConfigSchema, N
6
6
  const NOTION_API_BASE = "https://api.notion.com/v1";
7
7
  /** Default Notion API version. */
8
8
  const NOTION_API_VERSION = "2022-06-28";
9
- /** Module-level Notion configuration. */
10
- let config = null;
11
- /**
12
- * Retrieves the registered Notion config, or `null` when not configured.
13
- * @internal
14
- */
15
- function getConfig() {
16
- return config;
17
- }
18
9
  /** Builds a throwable error carrying `status`/`details` for `useAttempt`. */
19
10
  function apiError(message, status, details) {
20
11
  return Object.assign(new Error(message), { status, details });
21
12
  }
22
13
  /**
23
- * Internal helper to make authenticated requests to the Notion API.
24
- * Handles Authorization header, Notion-Version, and JSON serialization.
25
- * @internal
14
+ * NotionService - Singleton para el cliente de la Notion API.
15
+ *
16
+ * Aplica el patrón Singleton: una única instancia mantiene la configuración
17
+ * (token, versión, base URL) y centraliza las operaciones sobre páginas,
18
+ * bloques, bases de datos, usuarios y búsqueda, devolviendo siempre Safe Results.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const notion = NotionService.getInstance();
23
+ * notion.useInit({ token: process.env.NOTION_TOKEN });
24
+ * const result = await notion.useGetPage("page-id");
25
+ * ```
26
26
  */
27
- async function notionFetch(endpoint, options = {}, schema) {
28
- const cfg = getConfig();
29
- if (!cfg) {
30
- return {
31
- data: null,
32
- error: { message: "[Notion] Not configured. Call defineNotionConfig() first.", status: 0 },
33
- url: "",
34
- status: 0,
35
- ok: false,
36
- };
27
+ export class NotionService {
28
+ static instance;
29
+ /** Registered Notion configuration. */
30
+ config = null;
31
+ /**
32
+ * Constructor privado - enforce singleton.
33
+ */
34
+ constructor() { }
35
+ /**
36
+ * Obtiene la instancia única del NotionService (Singleton).
37
+ *
38
+ * @returns La instancia única de {@link NotionService}.
39
+ */
40
+ static getInstance() {
41
+ if (!NotionService.instance) {
42
+ NotionService.instance = new NotionService();
43
+ }
44
+ return NotionService.instance;
37
45
  }
38
- const { token, apiVersion, apiBaseUrl } = cfg;
39
- const base = apiBaseUrl ?? NOTION_API_BASE;
40
- const version = apiVersion ?? NOTION_API_VERSION;
41
- const url = `${base}${endpoint}`;
42
- const attempt = await useAttempt(async () => {
43
- const response = await fetch(url, {
44
- ...options,
45
- headers: {
46
- Authorization: `Bearer ${token}`,
47
- "Notion-Version": version,
48
- "Content-Type": "application/json",
49
- ...options.headers,
50
- },
51
- });
52
- if (!response.ok) {
53
- const errorBody = await response.text().catch(() => null);
54
- throw apiError(`Notion API Error: ${response.statusText}`, response.status, errorBody);
46
+ /**
47
+ * Registers the Notion API configuration.
48
+ *
49
+ * @param cfg - Integration token (starts with "ntn_" or "secret_"), optional
50
+ * API version and base URL.
51
+ * @throws {Error} If the config fails Zod validation.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * NotionService.getInstance().useInit({ token: process.env.NOTION_TOKEN });
56
+ * ```
57
+ */
58
+ useInit(cfg) {
59
+ const parsed = useValidate(NotionConfigSchema, cfg);
60
+ if (!parsed.ok) {
61
+ throw new Error("[Notion] Invalid config: " + parsed.error.message);
62
+ }
63
+ this.config = { ...parsed.data };
64
+ }
65
+ /**
66
+ * Internal helper to make authenticated requests to the Notion API.
67
+ * Handles Authorization header, Notion-Version, and JSON serialization.
68
+ * @internal
69
+ */
70
+ async useRequest(endpoint, options = {}, schema) {
71
+ const cfg = this.config;
72
+ if (!cfg) {
73
+ return {
74
+ data: null,
75
+ error: {
76
+ message: "[Notion] Not configured. Call defineNotionConfig() first.",
77
+ status: 0,
78
+ },
79
+ url: "",
80
+ status: 0,
81
+ ok: false,
82
+ };
55
83
  }
56
- if (response.status === 204) {
57
- return { data: null, status: 204 };
84
+ const { token, apiVersion, apiBaseUrl } = cfg;
85
+ const base = apiBaseUrl ?? NOTION_API_BASE;
86
+ const version = apiVersion ?? NOTION_API_VERSION;
87
+ const url = `${base}${endpoint}`;
88
+ const attempt = await useAttempt(async () => {
89
+ const response = await fetch(url, {
90
+ ...options,
91
+ headers: {
92
+ Authorization: `Bearer ${token}`,
93
+ "Notion-Version": version,
94
+ "Content-Type": "application/json",
95
+ ...options.headers,
96
+ },
97
+ });
98
+ if (!response.ok) {
99
+ const errorBody = await response.text().catch(() => null);
100
+ throw apiError(`Notion API Error: ${response.statusText}`, response.status, errorBody);
101
+ }
102
+ if (response.status === 204) {
103
+ return { data: null, status: 204 };
104
+ }
105
+ const data = (await response.json());
106
+ if (schema) {
107
+ const parsed = useValidate(schema, data);
108
+ if (!parsed.ok) {
109
+ throw apiError("Notion Validation Error: " + parsed.error.message, 502, parsed.error.details);
110
+ }
111
+ return { data: parsed.data, status: response.status };
112
+ }
113
+ return { data: data, status: response.status };
114
+ });
115
+ if (!attempt.ok) {
116
+ const { message, status, details } = attempt.error;
117
+ return {
118
+ data: null,
119
+ error: {
120
+ message: status === 0 ? `Network Error: ${message}` : message,
121
+ status,
122
+ details,
123
+ },
124
+ url,
125
+ status,
126
+ ok: false,
127
+ };
58
128
  }
59
- const data = (await response.json());
60
- if (schema) {
61
- const parsed = useValidate(schema, data);
129
+ return { data: attempt.data.data, error: null, url, status: attempt.data.status, ok: true };
130
+ }
131
+ /* ---------------------------------------------------------------------- */
132
+ /* Pages */
133
+ /* ---------------------------------------------------------------------- */
134
+ /** Retrieves a single Notion page by its ID. */
135
+ async useGetPage(pageId) {
136
+ return this.useRequest(`/pages/${pageId}`, {}, NotionPageResponseSchema);
137
+ }
138
+ /** Creates a new Notion page inside a database or as a child of another page. */
139
+ async useCreatePage(parent, properties, children) {
140
+ // Payload is Record<string, unknown>: no strict shape possible, skip input validation.
141
+ return this.useRequest("/pages", { method: "POST", body: JSON.stringify({ parent, properties, children }) }, NotionPageResponseSchema);
142
+ }
143
+ /** Updates properties of an existing Notion page. */
144
+ async useUpdatePage(pageId, properties) {
145
+ // Payload is Record<string, unknown>: no strict shape possible, skip input validation.
146
+ return this.useRequest(`/pages/${pageId}`, { method: "PATCH", body: JSON.stringify({ properties }) }, NotionPageResponseSchema);
147
+ }
148
+ /** Archives (soft-deletes) a Notion page. */
149
+ async useArchivePage(pageId) {
150
+ return this.useRequest(`/pages/${pageId}`, { method: "PATCH", body: JSON.stringify({ archived: true }) }, NotionPageResponseSchema);
151
+ }
152
+ /* ---------------------------------------------------------------------- */
153
+ /* Blocks */
154
+ /* ---------------------------------------------------------------------- */
155
+ /** Retrieves a single Notion block by its ID. */
156
+ async useGetBlock(blockId) {
157
+ return this.useRequest(`/blocks/${blockId}`, {}, NotionBlockResponseSchema);
158
+ }
159
+ /**
160
+ * Retrieves the direct children blocks of a block (single page).
161
+ *
162
+ * Use for manual pagination. For most cases, prefer
163
+ * {@link useListAllBlockChildren} which handles pagination automatically.
164
+ *
165
+ * @param blockId - The parent block ID (usually a page ID).
166
+ * @param options - Pagination: `start_cursor` for next page, `page_size` (max 100).
167
+ */
168
+ async useGetBlockChildren(blockId, options) {
169
+ const params = new URLSearchParams();
170
+ if (options?.start_cursor)
171
+ params.set("start_cursor", options.start_cursor);
172
+ if (options?.page_size)
173
+ params.set("page_size", String(options.page_size));
174
+ const qs = params.toString();
175
+ return this.useRequest(`/blocks/${blockId}/children${qs ? `?${qs}` : ""}`, {}, NotionBlockListSchema);
176
+ }
177
+ /** Appends new child blocks to a parent block. */
178
+ async useAppendBlocks(blockId, children) {
179
+ // Payload is unknown[]: no strict shape possible, skip input validation.
180
+ return this.useRequest(`/blocks/${blockId}/children`, { method: "PATCH", body: JSON.stringify({ children }) }, NotionBlockResponseSchema);
181
+ }
182
+ /** Updates the content of an existing block. */
183
+ async useUpdateBlock(blockId, content) {
184
+ // Payload is Record<string, unknown>: no strict shape possible, skip input validation.
185
+ return this.useRequest(`/blocks/${blockId}`, { method: "PATCH", body: JSON.stringify(content) }, NotionBlockResponseSchema);
186
+ }
187
+ /** Deletes (archives) a Notion block. The block is soft-deleted. */
188
+ async useDeleteBlock(blockId) {
189
+ return this.useRequest(`/blocks/${blockId}`, { method: "DELETE" }, NotionBlockResponseSchema);
190
+ }
191
+ /* ---------------------------------------------------------------------- */
192
+ /* Databases */
193
+ /* ---------------------------------------------------------------------- */
194
+ /** Retrieves a Notion database schema by its ID. */
195
+ async useGetDatabase(databaseId) {
196
+ return this.useRequest(`/databases/${databaseId}`, {}, NotionDatabaseResponseSchema);
197
+ }
198
+ /**
199
+ * Queries a Notion database with filters and sorts (single page).
200
+ *
201
+ * For most cases, prefer {@link useListAllDatabasePages} which handles
202
+ * pagination automatically.
203
+ */
204
+ async useQueryDatabase(databaseId, query) {
205
+ if (query !== undefined) {
206
+ const parsed = useValidate(NotionDatabaseQuerySchema, query);
62
207
  if (!parsed.ok) {
63
- throw apiError("Notion Validation Error: " + parsed.error.message, 502, parsed.error.details);
208
+ return { data: null, error: parsed.error, url: "", status: parsed.status, ok: false };
64
209
  }
65
- return { data: parsed.data, status: response.status };
66
210
  }
67
- return { data: data, status: response.status };
68
- });
69
- if (!attempt.ok) {
70
- const { message, status, details } = attempt.error;
211
+ return this.useRequest(`/databases/${databaseId}/query`, { method: "POST", body: JSON.stringify(query ?? {}) }, NotionPageListSchema);
212
+ }
213
+ /** Creates a new Notion database inside a page. */
214
+ async useCreateDatabase(parent, title, properties) {
215
+ // Payload properties are Record<string, NotionPropertySchema>: free-form, skip input validation.
216
+ return this.useRequest("/databases", { method: "POST", body: JSON.stringify({ parent, title, properties }) }, NotionDatabaseResponseSchema);
217
+ }
218
+ /** Updates a Notion database title and/or property schemas. */
219
+ async useUpdateDatabase(databaseId, title, properties) {
220
+ const body = { title };
221
+ if (properties)
222
+ body.properties = properties;
223
+ // Payload properties are Record<string, NotionPropertySchema>: free-form, skip input validation.
224
+ return this.useRequest(`/databases/${databaseId}`, { method: "PATCH", body: JSON.stringify(body) }, NotionDatabaseResponseSchema);
225
+ }
226
+ /* ---------------------------------------------------------------------- */
227
+ /* Users */
228
+ /* ---------------------------------------------------------------------- */
229
+ /** Retrieves a Notion workspace member or bot by their user ID. */
230
+ async useGetUser(userId) {
231
+ return this.useRequest(`/users/${userId}`, {}, NotionUserResponseSchema);
232
+ }
233
+ /** Lists all users (members + bots) in the workspace (paginated). */
234
+ async useListUsers(options) {
235
+ const params = new URLSearchParams();
236
+ if (options?.start_cursor)
237
+ params.set("start_cursor", options.start_cursor);
238
+ if (options?.page_size)
239
+ params.set("page_size", String(options.page_size));
240
+ const qs = params.toString();
241
+ return this.useRequest(`/users${qs ? `?${qs}` : ""}`, {}, NotionUserListSchema);
242
+ }
243
+ /* ---------------------------------------------------------------------- */
244
+ /* Search */
245
+ /* ---------------------------------------------------------------------- */
246
+ /** Searches across all pages and databases the integration has access to. */
247
+ async useSearchContent(query) {
248
+ const parsed = useValidate(NotionSearchQuerySchema, query);
249
+ if (!parsed.ok) {
250
+ return { data: null, error: parsed.error, url: "", status: parsed.status, ok: false };
251
+ }
252
+ return this.useRequest("/search", { method: "POST", body: JSON.stringify(query) }, NotionSearchResultSchema);
253
+ }
254
+ /* ---------------------------------------------------------------------- */
255
+ /* Pagination Helpers */
256
+ /* ---------------------------------------------------------------------- */
257
+ /**
258
+ * Fetches ALL child blocks of a block, automatically handling cursor pagination.
259
+ *
260
+ * @param blockId - The parent block ID (usually a page ID).
261
+ * @param maxItems - Cap on the total number of blocks to fetch (default `1000`).
262
+ * @returns All child blocks as a flat array.
263
+ */
264
+ async useListAllBlockChildren(blockId, maxItems = 1000) {
265
+ const allBlocks = [];
266
+ let cursor;
267
+ do {
268
+ const result = await this.useGetBlockChildren(blockId, {
269
+ start_cursor: cursor,
270
+ page_size: 100,
271
+ });
272
+ if (!result.ok)
273
+ return result;
274
+ allBlocks.push(...result.data.results);
275
+ if (maxItems && allBlocks.length >= maxItems)
276
+ break;
277
+ cursor = result.data.has_more ? (result.data.next_cursor ?? undefined) : undefined;
278
+ } while (cursor);
279
+ return {
280
+ data: allBlocks.slice(0, maxItems),
281
+ error: null,
282
+ url: "",
283
+ status: 200,
284
+ ok: true,
285
+ };
286
+ }
287
+ /**
288
+ * Fetches ALL pages in a database, automatically handling cursor pagination.
289
+ *
290
+ * @param databaseId - The database UUID.
291
+ * @param filter - Optional filter to apply (same syntax as Notion API).
292
+ * @param sorts - Optional sort options.
293
+ * @param maxItems - Cap on the total number of pages to fetch (default `1000`).
294
+ * @returns All pages matching the filter as a flat array.
295
+ */
296
+ async useListAllDatabasePages(databaseId, filter, sorts, maxItems = 1000) {
297
+ const allPages = [];
298
+ let cursor;
299
+ do {
300
+ const result = await this.useQueryDatabase(databaseId, {
301
+ filter,
302
+ sorts,
303
+ start_cursor: cursor,
304
+ page_size: 100,
305
+ });
306
+ if (!result.ok)
307
+ return result;
308
+ allPages.push(...result.data.results);
309
+ if (maxItems && allPages.length >= maxItems)
310
+ break;
311
+ cursor = result.data.has_more ? (result.data.next_cursor ?? undefined) : undefined;
312
+ } while (cursor);
71
313
  return {
72
- data: null,
73
- error: { message: status === 0 ? `Network Error: ${message}` : message, status, details },
74
- url,
75
- status,
76
- ok: false,
314
+ data: allPages.slice(0, maxItems),
315
+ error: null,
316
+ url: "",
317
+ status: 200,
318
+ ok: true,
77
319
  };
78
320
  }
79
- return { data: attempt.data.data, error: null, url, status: attempt.data.status, ok: true };
80
321
  }
81
322
  /* -------------------------------------------------------------------------- */
82
323
  /* Initialization */
83
324
  /* -------------------------------------------------------------------------- */
84
325
  /**
85
- * Registers the Notion configuration and returns your methods alongside it —
326
+ * Registers the Notion configuration and returns your methods alongside it -
86
327
  * the config-file entry point. One call is the whole setup: no separate
87
328
  * `useInitNotion(...)` step.
88
329
  *
@@ -130,21 +371,14 @@ export function defineNotionConfig(input) {
130
371
  * ```
131
372
  */
132
373
  export function useInitNotion(cfg) {
133
- const parsed = useValidate(NotionConfigSchema, cfg);
134
- if (!parsed.ok) {
135
- throw new Error("[Notion] Invalid config: " + parsed.error.message);
136
- }
137
- config = { ...parsed.data };
374
+ NotionService.getInstance().useInit(cfg);
138
375
  }
139
376
  /* -------------------------------------------------------------------------- */
140
- /* Pages */
377
+ /* Wrappers (backward compatibility) */
141
378
  /* -------------------------------------------------------------------------- */
142
379
  /**
143
380
  * Retrieves a single Notion page by its ID.
144
381
  *
145
- * Use when you need the full page object including all its properties
146
- * (title, status, dates, relations, etc.).
147
- *
148
382
  * @param pageId - The page UUID.
149
383
  * @returns The page object with all its properties.
150
384
  *
@@ -155,77 +389,44 @@ export function useInitNotion(cfg) {
155
389
  * ```
156
390
  */
157
391
  export async function useNotionGetPage(pageId) {
158
- return notionFetch(`/pages/${pageId}`, {}, NotionPageResponseSchema);
392
+ return NotionService.getInstance().useGetPage(pageId);
159
393
  }
160
394
  /**
161
395
  * Creates a new Notion page inside a database or as a child of another page.
162
396
  *
163
- * Use to add new entries to a database (tasks, notes, CRM records) or to
164
- * create nested page structures.
165
- *
166
- * @param parent - Where to create the page: `{ type: "database_id", database_id }`
167
- * for database entries, or `{ type: "page_id", page_id }` for child pages.
397
+ * @param parent - Where to create the page (`database_id` or `page_id`).
168
398
  * @param properties - Page properties matching the parent database schema.
169
399
  * @param children - Optional block children to populate the page content.
170
400
  * @returns The created page.
171
401
  *
172
402
  * @example
173
403
  * ```ts
174
- * // Add a task to a database
175
404
  * const result = await useNotionCreatePage(
176
405
  * { type: "database_id", database_id: "db-id" },
177
406
  * { Name: { title: [{ type: "text", text: { content: "My Task" } }] } },
178
407
  * );
179
- *
180
- * // Create a child page with content
181
- * const result = await useNotionCreatePage(
182
- * { type: "page_id", page_id: "parent-id" },
183
- * { title: { title: [{ type: "text", text: { content: "Child Page" } }] } },
184
- * [{ type: "paragraph", paragraph: { rich_text: [{ type: "text", text: { content: "Hello!" } }] } }],
185
- * );
186
408
  * ```
187
409
  */
188
410
  export async function useNotionCreatePage(parent, properties, children) {
189
- // Payload is Record<string, unknown>: no strict shape possible, skip input validation.
190
- return notionFetch("/pages", {
191
- method: "POST",
192
- body: JSON.stringify({ parent, properties, children }),
193
- }, NotionPageResponseSchema);
411
+ return NotionService.getInstance().useCreatePage(parent, properties, children);
194
412
  }
195
413
  /**
196
414
  * Updates properties of an existing Notion page.
197
415
  *
198
- * Use to change a page's status, dates, relations, or any other property
199
- * without touching the page content (blocks).
200
- *
201
416
  * @param pageId - The page UUID to update.
202
417
  * @param properties - Properties to update (only changed properties).
203
418
  * @returns The updated page.
204
419
  *
205
420
  * @example
206
421
  * ```ts
207
- * // Mark a task as done
208
- * await useNotionUpdatePage("page-id", {
209
- * Status: { select: { name: "Done" } },
210
- * });
211
- *
212
- * // Update multiple properties
213
- * await useNotionUpdatePage("page-id", {
214
- * Priority: { select: { name: "High" } },
215
- * DueDate: { date: { start: "2025-12-31" } },
216
- * });
422
+ * await useNotionUpdatePage("page-id", { Status: { select: { name: "Done" } } });
217
423
  * ```
218
424
  */
219
425
  export async function useNotionUpdatePage(pageId, properties) {
220
- // Payload is Record<string, unknown>: no strict shape possible, skip input validation.
221
- return notionFetch(`/pages/${pageId}`, {
222
- method: "PATCH",
223
- body: JSON.stringify({ properties }),
224
- }, NotionPageResponseSchema);
426
+ return NotionService.getInstance().useUpdatePage(pageId, properties);
225
427
  }
226
428
  /**
227
- * Archives (soft-deletes) a Notion page. The page becomes hidden but
228
- * can be restored from Notion's trash.
429
+ * Archives (soft-deletes) a Notion page.
229
430
  *
230
431
  * @param pageId - The page UUID to archive.
231
432
  * @returns The archived page.
@@ -236,69 +437,40 @@ export async function useNotionUpdatePage(pageId, properties) {
236
437
  * ```
237
438
  */
238
439
  export async function useNotionArchivePage(pageId) {
239
- return notionFetch(`/pages/${pageId}`, {
240
- method: "PATCH",
241
- body: JSON.stringify({ archived: true }),
242
- }, NotionPageResponseSchema);
440
+ return NotionService.getInstance().useArchivePage(pageId);
243
441
  }
244
- /* -------------------------------------------------------------------------- */
245
- /* Blocks */
246
- /* -------------------------------------------------------------------------- */
247
442
  /**
248
443
  * Retrieves a single Notion block by its ID.
249
444
  *
250
- * A block is any content element: paragraph, heading, list item, image,
251
- * table, callout, etc. Use to inspect a specific block's type and content.
252
- *
253
445
  * @param blockId - The block UUID.
254
446
  * @returns The block object with its type-specific content.
255
447
  *
256
448
  * @example
257
449
  * ```ts
258
450
  * const result = await useNotionGetBlock("block-id");
259
- * if (result.ok) console.log(result.data.type); // "paragraph", "heading_1", etc.
260
451
  * ```
261
452
  */
262
453
  export async function useNotionGetBlock(blockId) {
263
- return notionFetch(`/blocks/${blockId}`, {}, NotionBlockResponseSchema);
454
+ return NotionService.getInstance().useGetBlock(blockId);
264
455
  }
265
456
  /**
266
457
  * Retrieves the direct children blocks of a block (single page).
267
458
  *
268
- * Use for manual pagination when you need fine-grained control over
269
- * cursor-based pagination. For most cases, prefer
270
- * {@link useNotionListAllBlockChildren} which handles pagination automatically.
271
- *
272
459
  * @param blockId - The parent block ID (usually a page ID).
273
- * @param options - Pagination: `start_cursor` for next page, `page_size` (max 100).
274
- * @returns Paginated list of child blocks with `has_more` and `next_cursor`.
460
+ * @param options - Pagination: `start_cursor`, `page_size` (max 100).
461
+ * @returns Paginated list of child blocks.
275
462
  *
276
463
  * @example
277
464
  * ```ts
278
465
  * const result = await useNotionGetBlockChildren("page-id");
279
- * if (result.ok) {
280
- * console.log(result.data.results); // First page of blocks
281
- * if (result.data.has_more) {
282
- * // Fetch next page with result.data.next_cursor
283
- * }
284
- * }
285
466
  * ```
286
467
  */
287
468
  export async function useNotionGetBlockChildren(blockId, options) {
288
- const params = new URLSearchParams();
289
- if (options?.start_cursor)
290
- params.set("start_cursor", options.start_cursor);
291
- if (options?.page_size)
292
- params.set("page_size", String(options.page_size));
293
- const qs = params.toString();
294
- return notionFetch(`/blocks/${blockId}/children${qs ? `?${qs}` : ""}`, {}, NotionBlockListSchema);
469
+ return NotionService.getInstance().useGetBlockChildren(blockId, options);
295
470
  }
296
471
  /**
297
472
  * Appends new child blocks to a parent block.
298
473
  *
299
- * Use to add content to a page: paragraphs, headings, lists, toggles,
300
- * code blocks, etc. Blocks are appended at the end.
301
- *
302
474
  * @param blockId - The parent block ID (usually a page ID).
303
475
  * @param children - Array of block objects to append.
304
476
  * @returns The parent block.
@@ -306,32 +478,18 @@ export async function useNotionGetBlockChildren(blockId, options) {
306
478
  * @example
307
479
  * ```ts
308
480
  * await useNotionAppendBlocks("page-id", [
309
- * {
310
- * type: "heading_2",
311
- * heading_2: { rich_text: [{ type: "text", text: { content: "Section Title" } }] },
312
- * },
313
- * {
314
- * type: "paragraph",
315
- * paragraph: { rich_text: [{ type: "text", text: { content: "Body text here." } }] },
316
- * },
481
+ * { type: "paragraph", paragraph: { rich_text: [{ type: "text", text: { content: "Hi" } }] } },
317
482
  * ]);
318
483
  * ```
319
484
  */
320
485
  export async function useNotionAppendBlocks(blockId, children) {
321
- // Payload is unknown[]: no strict shape possible, skip input validation.
322
- return notionFetch(`/blocks/${blockId}/children`, {
323
- method: "PATCH",
324
- body: JSON.stringify({ children }),
325
- }, NotionBlockResponseSchema);
486
+ return NotionService.getInstance().useAppendBlocks(blockId, children);
326
487
  }
327
488
  /**
328
489
  * Updates the content of an existing block.
329
490
  *
330
- * Use to modify text, toggle content, code blocks, etc. without
331
- * deleting and recreating the block.
332
- *
333
491
  * @param blockId - The block UUID to update.
334
- * @param content - The new content for the block type (e.g. `{ paragraph: { rich_text: [...] } }`).
492
+ * @param content - The new content for the block type.
335
493
  * @returns The updated block.
336
494
  *
337
495
  * @example
@@ -342,15 +500,10 @@ export async function useNotionAppendBlocks(blockId, children) {
342
500
  * ```
343
501
  */
344
502
  export async function useNotionUpdateBlock(blockId, content) {
345
- // Payload is Record<string, unknown>: no strict shape possible, skip input validation.
346
- return notionFetch(`/blocks/${blockId}`, {
347
- method: "PATCH",
348
- body: JSON.stringify(content),
349
- }, NotionBlockResponseSchema);
503
+ return NotionService.getInstance().useUpdateBlock(blockId, content);
350
504
  }
351
505
  /**
352
- * Deletes (archives) a Notion block. The block is soft-deleted and
353
- * can be restored.
506
+ * Deletes (archives) a Notion block.
354
507
  *
355
508
  * @param blockId - The block UUID to delete.
356
509
  * @returns The deleted block.
@@ -361,81 +514,45 @@ export async function useNotionUpdateBlock(blockId, content) {
361
514
  * ```
362
515
  */
363
516
  export async function useNotionDeleteBlock(blockId) {
364
- return notionFetch(`/blocks/${blockId}`, {
365
- method: "DELETE",
366
- }, NotionBlockResponseSchema);
517
+ return NotionService.getInstance().useDeleteBlock(blockId);
367
518
  }
368
- /* -------------------------------------------------------------------------- */
369
- /* Databases */
370
- /* -------------------------------------------------------------------------- */
371
519
  /**
372
520
  * Retrieves a Notion database schema by its ID.
373
521
  *
374
- * Use to inspect the database structure: property names, types, and
375
- * configuration (select options, formula definitions, etc.).
376
- *
377
522
  * @param databaseId - The database UUID.
378
523
  * @returns The database object with its full property schema.
379
524
  *
380
525
  * @example
381
526
  * ```ts
382
527
  * const result = await useNotionGetDatabase("db-id");
383
- * if (result.ok) {
384
- * // See all available properties
385
- * Object.entries(result.data.properties).forEach(([name, prop]) => {
386
- * console.log(`${name}: ${prop.type}`);
387
- * });
388
- * }
389
528
  * ```
390
529
  */
391
530
  export async function useNotionGetDatabase(databaseId) {
392
- return notionFetch(`/databases/${databaseId}`, {}, NotionDatabaseResponseSchema);
531
+ return NotionService.getInstance().useGetDatabase(databaseId);
393
532
  }
394
533
  /**
395
534
  * Queries a Notion database with filters and sorts (single page).
396
535
  *
397
- * Use for manual pagination or when you only need the first page of
398
- * results. For most cases, prefer {@link useNotionListAllDatabasePages}
399
- * which handles pagination automatically.
400
- *
401
536
  * @param databaseId - The database UUID to query.
402
537
  * @param query - Filter, sort, and pagination options.
403
538
  * @returns Paginated list of pages matching the query.
404
539
  *
405
540
  * @example
406
541
  * ```ts
407
- * // Get first page of all entries
408
- * const all = await useNotionQueryDatabase("db-id");
409
- *
410
- * // With filter and sort
411
542
  * const filtered = await useNotionQueryDatabase("db-id", {
412
543
  * filter: { property: "Status", select: { equals: "Done" } },
413
- * sorts: [{ property: "Date", direction: "descending" }],
414
- * page_size: 10,
415
544
  * });
416
545
  * ```
417
546
  */
418
547
  export async function useNotionQueryDatabase(databaseId, query) {
419
- if (query !== undefined) {
420
- const parsed = useValidate(NotionDatabaseQuerySchema, query);
421
- if (!parsed.ok) {
422
- return { data: null, error: parsed.error, url: "", status: parsed.status, ok: false };
423
- }
424
- }
425
- return notionFetch(`/databases/${databaseId}/query`, {
426
- method: "POST",
427
- body: JSON.stringify(query ?? {}),
428
- }, NotionPageListSchema);
548
+ return NotionService.getInstance().useQueryDatabase(databaseId, query);
429
549
  }
430
550
  /**
431
551
  * Creates a new Notion database inside a page.
432
552
  *
433
- * Use to programmatically create structured databases with custom
434
- * property schemas (select options, formulas, relations, etc.).
435
- *
436
553
  * @param parent - The parent page (`{ type: "page_id", page_id }`).
437
554
  * @param title - Database title as rich text array.
438
- * @param properties - Property schema definitions (Name, Status, Date, etc.).
555
+ * @param properties - Property schema definitions.
439
556
  * @returns The created database.
440
557
  *
441
558
  * @example
@@ -443,26 +560,16 @@ export async function useNotionQueryDatabase(databaseId, query) {
443
560
  * await useNotionCreateDatabase(
444
561
  * { type: "page_id", page_id: "parent-id" },
445
562
  * [{ type: "text", text: { content: "My Tasks" } }],
446
- * {
447
- * Name: { title: {} },
448
- * Status: { select: { options: [{ name: "To Do" }, { name: "Done" }] } },
449
- * Priority: { select: { options: [{ name: "Low" }, { name: "High" }] } },
450
- * },
563
+ * { Name: { title: {} } },
451
564
  * );
452
565
  * ```
453
566
  */
454
567
  export async function useNotionCreateDatabase(parent, title, properties) {
455
- // Payload properties are Record<string, NotionPropertySchema>: free-form, skip input validation.
456
- return notionFetch("/databases", {
457
- method: "POST",
458
- body: JSON.stringify({ parent, title, properties }),
459
- }, NotionDatabaseResponseSchema);
568
+ return NotionService.getInstance().useCreateDatabase(parent, title, properties);
460
569
  }
461
570
  /**
462
571
  * Updates a Notion database title and/or property schemas.
463
572
  *
464
- * Use to rename a database or add/modify property definitions.
465
- *
466
573
  * @param databaseId - The database UUID to update.
467
574
  * @param title - New title as rich text array.
468
575
  * @param properties - Optional property schema updates to merge.
@@ -470,116 +577,57 @@ export async function useNotionCreateDatabase(parent, title, properties) {
470
577
  *
471
578
  * @example
472
579
  * ```ts
473
- * await useNotionUpdateDatabase("db-id", [
474
- * { type: "text", text: { content: "Renamed Database" } },
475
- * ]);
580
+ * await useNotionUpdateDatabase("db-id", [{ type: "text", text: { content: "Renamed" } }]);
476
581
  * ```
477
582
  */
478
583
  export async function useNotionUpdateDatabase(databaseId, title, properties) {
479
- const body = { title };
480
- if (properties)
481
- body.properties = properties;
482
- // Payload properties are Record<string, NotionPropertySchema>: free-form, skip input validation.
483
- return notionFetch(`/databases/${databaseId}`, {
484
- method: "PATCH",
485
- body: JSON.stringify(body),
486
- }, NotionDatabaseResponseSchema);
584
+ return NotionService.getInstance().useUpdateDatabase(databaseId, title, properties);
487
585
  }
488
- /* -------------------------------------------------------------------------- */
489
- /* Users */
490
- /* -------------------------------------------------------------------------- */
491
586
  /**
492
587
  * Retrieves a Notion workspace member or bot by their user ID.
493
588
  *
494
- * Use to get display name, avatar, or email of the person who created
495
- * or last edited a page.
496
- *
497
- * @param userId - The user UUID (from page.created_by.id or page.last_edited_by.id).
589
+ * @param userId - The user UUID.
498
590
  * @returns The user object.
499
591
  *
500
592
  * @example
501
593
  * ```ts
502
594
  * const result = await useNotionGetUser("user-id");
503
- * if (result.ok) console.log(result.data.name);
504
595
  * ```
505
596
  */
506
597
  export async function useNotionGetUser(userId) {
507
- return notionFetch(`/users/${userId}`, {}, NotionUserResponseSchema);
598
+ return NotionService.getInstance().useGetUser(userId);
508
599
  }
509
600
  /**
510
601
  * Lists all users (members + bots) in the workspace (paginated).
511
602
  *
512
- * Use to enumerate workspace members for assignment, mention, or
513
- * permission checks.
514
- *
515
603
  * @param options - Pagination: `start_cursor`, `page_size` (max 100).
516
604
  * @returns Paginated list of users.
517
605
  *
518
606
  * @example
519
607
  * ```ts
520
608
  * const result = await useNotionListUsers();
521
- * if (result.ok) result.data.results.forEach(u => console.log(u.name));
522
609
  * ```
523
610
  */
524
611
  export async function useNotionListUsers(options) {
525
- const params = new URLSearchParams();
526
- if (options?.start_cursor)
527
- params.set("start_cursor", options.start_cursor);
528
- if (options?.page_size)
529
- params.set("page_size", String(options.page_size));
530
- const qs = params.toString();
531
- return notionFetch(`/users${qs ? `?${qs}` : ""}`, {}, NotionUserListSchema);
612
+ return NotionService.getInstance().useListUsers(options);
532
613
  }
533
- /* -------------------------------------------------------------------------- */
534
- /* Search */
535
- /* -------------------------------------------------------------------------- */
536
614
  /**
537
615
  * Searches across all pages and databases the integration has access to.
538
616
  *
539
- * Use to find content by keyword when you don't have the page/database ID.
540
- * Supports filtering by object type (page or database) and sorting by
541
- * last edit time.
542
- *
543
617
  * @param query - Search options: text query, object type filter, sort direction.
544
618
  * @returns Paginated search results (mixed pages and databases).
545
619
  *
546
620
  * @example
547
621
  * ```ts
548
- * // Search everything for a keyword
549
622
  * const result = await useNotionSearchContent({ query: "meeting notes" });
550
- *
551
- * // Search only databases
552
- * const dbs = await useNotionSearchContent({
553
- * query: "tasks",
554
- * filter: { value: "database", property: "object" },
555
- * });
556
- *
557
- * // Search only pages, sorted by recent
558
- * const pages = await useNotionSearchContent({
559
- * filter: { value: "page", property: "object" },
560
- * sort: { direction: "descending", timestamp: "last_edited_time" },
561
- * });
562
623
  * ```
563
624
  */
564
625
  export async function useNotionSearchContent(query) {
565
- const parsed = useValidate(NotionSearchQuerySchema, query);
566
- if (!parsed.ok) {
567
- return { data: null, error: parsed.error, url: "", status: parsed.status, ok: false };
568
- }
569
- return notionFetch("/search", {
570
- method: "POST",
571
- body: JSON.stringify(query),
572
- }, NotionSearchResultSchema);
626
+ return NotionService.getInstance().useSearchContent(query);
573
627
  }
574
- /* -------------------------------------------------------------------------- */
575
- /* Pagination Helpers */
576
- /* -------------------------------------------------------------------------- */
577
628
  /**
578
629
  * Fetches ALL child blocks of a block, automatically handling cursor pagination.
579
630
  *
580
- * Use when you need the complete content of a page without worrying about
581
- * pagination cursors. Loops through all pages until `has_more` is false.
582
- *
583
631
  * @param blockId - The parent block ID (usually a page ID).
584
632
  * @param maxItems - Cap on the total number of blocks to fetch (default `1000`).
585
633
  * @returns All child blocks as a flat array.
@@ -587,42 +635,14 @@ export async function useNotionSearchContent(query) {
587
635
  * @example
588
636
  * ```ts
589
637
  * const result = await useNotionListAllBlockChildren("page-id");
590
- * if (result.ok) {
591
- * console.log(`Total blocks: ${result.data.length}`);
592
- * result.data.forEach(block => console.log(block.type));
593
- * }
594
638
  * ```
595
639
  */
596
640
  export async function useNotionListAllBlockChildren(blockId, maxItems = 1000) {
597
- const allBlocks = [];
598
- let cursor;
599
- do {
600
- const result = await useNotionGetBlockChildren(blockId, {
601
- start_cursor: cursor,
602
- page_size: 100,
603
- });
604
- if (!result.ok)
605
- return result;
606
- allBlocks.push(...result.data.results);
607
- if (maxItems && allBlocks.length >= maxItems)
608
- break;
609
- cursor = result.data.has_more ? (result.data.next_cursor ?? undefined) : undefined;
610
- } while (cursor);
611
- return {
612
- data: allBlocks.slice(0, maxItems),
613
- error: null,
614
- url: "",
615
- status: 200,
616
- ok: true,
617
- };
641
+ return NotionService.getInstance().useListAllBlockChildren(blockId, maxItems);
618
642
  }
619
643
  /**
620
644
  * Fetches ALL pages in a database, automatically handling cursor pagination.
621
645
  *
622
- * Use when you need every entry from a database without worrying about
623
- * pagination. Supports optional filters and sorts. Loops through all
624
- * pages until `has_more` is false.
625
- *
626
646
  * @param databaseId - The database UUID.
627
647
  * @param filter - Optional filter to apply (same syntax as Notion API).
628
648
  * @param sorts - Optional sort options.
@@ -631,41 +651,10 @@ export async function useNotionListAllBlockChildren(blockId, maxItems = 1000) {
631
651
  *
632
652
  * @example
633
653
  * ```ts
634
- * // Get ALL pages in a database
635
654
  * const result = await useNotionListAllDatabasePages("db-id");
636
- * if (result.ok) console.log(`Total entries: ${result.data.length}`);
637
- *
638
- * // Get only published pages, sorted by date
639
- * const published = await useNotionListAllDatabasePages(
640
- * "db-id",
641
- * { property: "Status", select: { equals: "Published" } },
642
- * [{ property: "Date", direction: "descending" }],
643
- * );
644
655
  * ```
645
656
  */
646
657
  export async function useNotionListAllDatabasePages(databaseId, filter, sorts, maxItems = 1000) {
647
- const allPages = [];
648
- let cursor;
649
- do {
650
- const result = await useNotionQueryDatabase(databaseId, {
651
- filter,
652
- sorts,
653
- start_cursor: cursor,
654
- page_size: 100,
655
- });
656
- if (!result.ok)
657
- return result;
658
- allPages.push(...result.data.results);
659
- if (maxItems && allPages.length >= maxItems)
660
- break;
661
- cursor = result.data.has_more ? (result.data.next_cursor ?? undefined) : undefined;
662
- } while (cursor);
663
- return {
664
- data: allPages.slice(0, maxItems),
665
- error: null,
666
- url: "",
667
- status: 200,
668
- ok: true,
669
- };
658
+ return NotionService.getInstance().useListAllDatabasePages(databaseId, filter, sorts, maxItems);
670
659
  }
671
660
  //# sourceMappingURL=notion.service.js.map