@infograb/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 (114) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1386 -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/batch/retrieve.d.ts +43 -0
  14. package/dist/commands/batch/retrieve.js +265 -0
  15. package/dist/commands/block/append.d.ts +42 -0
  16. package/dist/commands/block/append.js +219 -0
  17. package/dist/commands/block/delete.d.ts +30 -0
  18. package/dist/commands/block/delete.js +94 -0
  19. package/dist/commands/block/retrieve/children.d.ts +31 -0
  20. package/dist/commands/block/retrieve/children.js +174 -0
  21. package/dist/commands/block/retrieve.d.ts +30 -0
  22. package/dist/commands/block/retrieve.js +98 -0
  23. package/dist/commands/block/update.d.ts +45 -0
  24. package/dist/commands/block/update.js +241 -0
  25. package/dist/commands/cache/info.d.ts +19 -0
  26. package/dist/commands/cache/info.js +145 -0
  27. package/dist/commands/config/set-token.d.ts +30 -0
  28. package/dist/commands/config/set-token.js +201 -0
  29. package/dist/commands/db/create.d.ts +31 -0
  30. package/dist/commands/db/create.js +124 -0
  31. package/dist/commands/db/query.d.ts +41 -0
  32. package/dist/commands/db/query.js +355 -0
  33. package/dist/commands/db/retrieve.d.ts +33 -0
  34. package/dist/commands/db/retrieve.js +134 -0
  35. package/dist/commands/db/schema.d.ts +32 -0
  36. package/dist/commands/db/schema.js +308 -0
  37. package/dist/commands/db/update.d.ts +31 -0
  38. package/dist/commands/db/update.js +117 -0
  39. package/dist/commands/doctor.d.ts +50 -0
  40. package/dist/commands/doctor.js +420 -0
  41. package/dist/commands/init.d.ts +57 -0
  42. package/dist/commands/init.js +471 -0
  43. package/dist/commands/list.d.ts +29 -0
  44. package/dist/commands/list.js +184 -0
  45. package/dist/commands/page/create.d.ts +33 -0
  46. package/dist/commands/page/create.js +240 -0
  47. package/dist/commands/page/retrieve/property_item.d.ts +24 -0
  48. package/dist/commands/page/retrieve/property_item.js +72 -0
  49. package/dist/commands/page/retrieve.d.ts +36 -0
  50. package/dist/commands/page/retrieve.js +244 -0
  51. package/dist/commands/page/update.d.ts +34 -0
  52. package/dist/commands/page/update.js +184 -0
  53. package/dist/commands/search.d.ts +40 -0
  54. package/dist/commands/search.js +348 -0
  55. package/dist/commands/sync.d.ts +24 -0
  56. package/dist/commands/sync.js +183 -0
  57. package/dist/commands/user/list.d.ts +27 -0
  58. package/dist/commands/user/list.js +99 -0
  59. package/dist/commands/user/retrieve/bot.d.ts +28 -0
  60. package/dist/commands/user/retrieve/bot.js +96 -0
  61. package/dist/commands/user/retrieve.d.ts +30 -0
  62. package/dist/commands/user/retrieve.js +103 -0
  63. package/dist/commands/whoami.d.ts +19 -0
  64. package/dist/commands/whoami.js +175 -0
  65. package/dist/deduplication.d.ts +41 -0
  66. package/dist/deduplication.js +71 -0
  67. package/dist/envelope.d.ts +169 -0
  68. package/dist/envelope.js +257 -0
  69. package/dist/errors/enhanced-errors.d.ts +168 -0
  70. package/dist/errors/enhanced-errors.js +570 -0
  71. package/dist/errors/index.d.ts +18 -0
  72. package/dist/errors/index.js +33 -0
  73. package/dist/examples/cache-retry-examples.d.ts +64 -0
  74. package/dist/examples/cache-retry-examples.js +375 -0
  75. package/dist/helper.d.ts +102 -0
  76. package/dist/helper.js +885 -0
  77. package/dist/http-agent.d.ts +38 -0
  78. package/dist/http-agent.js +60 -0
  79. package/dist/index.d.ts +1 -0
  80. package/dist/index.js +4 -0
  81. package/dist/interface.d.ts +4 -0
  82. package/dist/interface.js +2 -0
  83. package/dist/notion.d.ts +144 -0
  84. package/dist/notion.js +547 -0
  85. package/dist/retry.d.ts +72 -0
  86. package/dist/retry.js +381 -0
  87. package/dist/utils/disk-cache.d.ts +80 -0
  88. package/dist/utils/disk-cache.js +291 -0
  89. package/dist/utils/markdown-to-blocks.d.ts +19 -0
  90. package/dist/utils/markdown-to-blocks.js +259 -0
  91. package/dist/utils/notion-resolver.d.ts +48 -0
  92. package/dist/utils/notion-resolver.js +262 -0
  93. package/dist/utils/notion-url-parser.d.ts +46 -0
  94. package/dist/utils/notion-url-parser.js +111 -0
  95. package/dist/utils/property-expander.d.ts +45 -0
  96. package/dist/utils/property-expander.js +323 -0
  97. package/dist/utils/schema-examples.d.ts +40 -0
  98. package/dist/utils/schema-examples.js +359 -0
  99. package/dist/utils/schema-extractor.d.ts +65 -0
  100. package/dist/utils/schema-extractor.js +235 -0
  101. package/dist/utils/table-formatter.d.ts +36 -0
  102. package/dist/utils/table-formatter.js +122 -0
  103. package/dist/utils/terminal-banner.d.ts +24 -0
  104. package/dist/utils/terminal-banner.js +34 -0
  105. package/dist/utils/token-validator.d.ts +55 -0
  106. package/dist/utils/token-validator.js +85 -0
  107. package/dist/utils/update-notifier.d.ts +26 -0
  108. package/dist/utils/update-notifier.js +54 -0
  109. package/dist/utils/workspace-cache.d.ts +58 -0
  110. package/dist/utils/workspace-cache.js +185 -0
  111. package/oclif.manifest.json +4497 -0
  112. package/package.json +115 -0
  113. package/scripts/banner.js +38 -0
  114. package/scripts/postinstall.js +56 -0
@@ -0,0 +1,262 @@
1
+ "use strict";
2
+ /**
3
+ * Notion ID Resolver
4
+ *
5
+ * Hybrid resolution system that supports:
6
+ * - URLs: https://www.notion.so/database-id
7
+ * - Direct IDs: database-id
8
+ * - Names: "Tasks Database" (via cache lookup and API fallback)
9
+ * - Smart database_id → data_source_id conversion
10
+ *
11
+ * Resolution stages:
12
+ * 1. URL extraction
13
+ * 2. Direct ID validation
14
+ * 3. Cache lookup (exact + aliases)
15
+ * 4. API search fallback
16
+ * 5. Smart database_id → data_source_id resolution (for databases)
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.resolveNotionId = resolveNotionId;
20
+ const notion_url_parser_1 = require("./notion-url-parser");
21
+ const errors_1 = require("../errors");
22
+ const workspace_cache_1 = require("./workspace-cache");
23
+ const notion_1 = require("../notion");
24
+ const client_1 = require("@notionhq/client");
25
+ /**
26
+ * Resolve Notion input (URL, ID, or name) to a clean Notion ID
27
+ *
28
+ * Supports URLs, IDs, and name-based lookups via cache and API search.
29
+ * For databases, automatically detects and converts database_id to data_source_id.
30
+ *
31
+ * @param input - Database/page name, ID, or URL
32
+ * @param type - Resource type (for better error messages)
33
+ * @returns Clean Notion ID (32 hex characters without dashes)
34
+ * @throws NotionCLIError if input cannot be resolved
35
+ *
36
+ * @example
37
+ * // URL
38
+ * await resolveNotionId('https://notion.so/1fb79d4c71bb8032b722c82305b63a00')
39
+ * // Returns: '1fb79d4c71bb8032b722c82305b63a00'
40
+ *
41
+ * @example
42
+ * // Direct ID
43
+ * await resolveNotionId('1fb79d4c71bb8032b722c82305b63a00')
44
+ * // Returns: '1fb79d4c71bb8032b722c82305b63a00'
45
+ *
46
+ * @example
47
+ * // Name (via cache or API)
48
+ * await resolveNotionId('Tasks Database', 'database')
49
+ * // Returns: '1fb79d4c71bb8032b722c82305b63a00'
50
+ *
51
+ * @example
52
+ * // database_id auto-conversion
53
+ * await resolveNotionId('abc123...', 'database')
54
+ * // If abc123 is a database_id, auto-resolves to data_source_id
55
+ */
56
+ async function resolveNotionId(input, type = 'database') {
57
+ if (!input || typeof input !== 'string') {
58
+ throw new errors_1.NotionCLIError(errors_1.NotionCLIErrorCode.VALIDATION_ERROR, `Invalid input: expected a ${type} name, ID, or URL`, [], { resourceType: type, userInput: String(input) });
59
+ }
60
+ const trimmed = input.trim();
61
+ // Stage 1: URL extraction
62
+ if ((0, notion_url_parser_1.isNotionUrl)(trimmed)) {
63
+ try {
64
+ const extractedId = (0, notion_url_parser_1.extractNotionId)(trimmed);
65
+ // For databases, try smart resolution in case URL contains database_id
66
+ if (type === 'database') {
67
+ return await trySmartDatabaseResolution(extractedId);
68
+ }
69
+ return extractedId;
70
+ }
71
+ catch {
72
+ throw errors_1.NotionCLIErrorFactory.invalidIdFormat(trimmed, type);
73
+ }
74
+ }
75
+ // Stage 2: Direct ID validation
76
+ if (isValidNotionId(trimmed)) {
77
+ const extractedId = (0, notion_url_parser_1.extractNotionId)(trimmed);
78
+ // For databases, try smart resolution in case it's a database_id
79
+ if (type === 'database') {
80
+ return await trySmartDatabaseResolution(extractedId);
81
+ }
82
+ return extractedId;
83
+ }
84
+ // Stage 3: Cache lookup (exact + aliases)
85
+ const fromCache = await searchCache(trimmed);
86
+ if (fromCache)
87
+ return fromCache;
88
+ // Stage 4: API search as fallback
89
+ const fromApi = await searchNotionApi(trimmed, type);
90
+ if (fromApi)
91
+ return fromApi;
92
+ // Nothing found - throw helpful error
93
+ if (type === 'database') {
94
+ throw errors_1.NotionCLIErrorFactory.workspaceNotSynced(trimmed);
95
+ }
96
+ throw errors_1.NotionCLIErrorFactory.resourceNotFound(type, trimmed);
97
+ }
98
+ /**
99
+ * Smart database resolution: handles database_id → data_source_id conversion
100
+ *
101
+ * When a user provides a database_id (from parent.database_id field),
102
+ * this function detects the error and automatically resolves it to the
103
+ * correct data_source_id.
104
+ *
105
+ * @param databaseId - Potential database_id or data_source_id
106
+ * @returns data_source_id if valid, throws error otherwise
107
+ */
108
+ async function trySmartDatabaseResolution(databaseId) {
109
+ try {
110
+ // Try direct lookup with data_source_id
111
+ await (0, notion_1.retrieveDataSource)(databaseId);
112
+ // If successful, it's a valid data_source_id
113
+ return databaseId;
114
+ }
115
+ catch (error) {
116
+ // Check if this is an object_not_found error (404)
117
+ const isNotFound = error.status === 404 ||
118
+ error.code === 'object_not_found' ||
119
+ (error.notionError && error.notionError.code === 'object_not_found');
120
+ if (isNotFound) {
121
+ // Try to resolve database_id → data_source_id
122
+ const dataSourceId = await resolveDatabaseIdToDataSourceId(databaseId);
123
+ if (dataSourceId) {
124
+ // Log helpful message about conversion
125
+ console.log(`\nInfo: Resolved database_id to data_source_id`);
126
+ console.log(` database_id: ${databaseId}`);
127
+ console.log(` data_source_id: ${dataSourceId}`);
128
+ console.log(`\nNote: Use data_source_id for database operations.`);
129
+ console.log(` The database_id from parent.database_id won't work directly.\n`);
130
+ return dataSourceId;
131
+ }
132
+ }
133
+ // If we can't resolve it, throw the original error
134
+ throw (0, errors_1.wrapNotionError)(error);
135
+ }
136
+ }
137
+ /**
138
+ * Resolve database_id to data_source_id by searching for pages
139
+ *
140
+ * When a user provides a database_id (from parent.database_id field),
141
+ * we search for pages that have this database as their parent, and
142
+ * extract the data_source_id from the parent field.
143
+ *
144
+ * @param databaseId - The database_id to resolve
145
+ * @returns data_source_id if found, null otherwise
146
+ */
147
+ async function resolveDatabaseIdToDataSourceId(databaseId) {
148
+ try {
149
+ // Search for pages with this database_id as parent
150
+ const response = await (0, notion_1.search)({
151
+ filter: {
152
+ property: 'object',
153
+ value: 'page'
154
+ },
155
+ page_size: 100 // Search more pages to increase chance of finding one
156
+ });
157
+ if (!response || !response.results || response.results.length === 0) {
158
+ return null;
159
+ }
160
+ // Look through results for a page with matching parent.database_id
161
+ for (const result of response.results) {
162
+ if (result.object !== 'page')
163
+ continue;
164
+ // Use type guard to ensure we have a full page with parent
165
+ if (!(0, client_1.isFullPage)(result))
166
+ continue;
167
+ // Check if parent type is database_id and matches our search
168
+ if (result.parent &&
169
+ result.parent.type === 'database_id' &&
170
+ result.parent.database_id === databaseId) {
171
+ // Extract data_source_id from the same parent object
172
+ // In the Notion API v5, pages have both database_id and data_source_id in parent
173
+ if ('data_source_id' in result.parent) {
174
+ return result.parent.data_source_id;
175
+ }
176
+ }
177
+ }
178
+ return null;
179
+ }
180
+ catch (error) {
181
+ // If search fails, return null and let the main error handling deal with it
182
+ if (process.env.DEBUG) {
183
+ console.error('Debug: Failed to resolve database_id to data_source_id:', error);
184
+ }
185
+ return null;
186
+ }
187
+ }
188
+ /**
189
+ * Check if a string is a valid Notion ID (32 hex chars with optional dashes)
190
+ */
191
+ function isValidNotionId(input) {
192
+ const cleaned = input.replace(/-/g, '');
193
+ return /^[a-f0-9]{32}$/i.test(cleaned);
194
+ }
195
+ /**
196
+ * Search cache for database/page by name
197
+ *
198
+ * Searches in this order:
199
+ * 1. Exact title match (case-insensitive)
200
+ * 2. Alias match (case-insensitive)
201
+ * 3. Partial title match (case-insensitive substring)
202
+ *
203
+ * @param query - Search query (database/page name)
204
+ * @returns Database/page ID if found, null otherwise
205
+ */
206
+ async function searchCache(query) {
207
+ const cache = await (0, workspace_cache_1.loadCache)();
208
+ if (!cache)
209
+ return null;
210
+ const normalized = query.toLowerCase().trim();
211
+ // 1. Try exact title match
212
+ for (const db of cache.databases) {
213
+ if (db.titleNormalized === normalized) {
214
+ return db.id;
215
+ }
216
+ }
217
+ // 2. Try alias match
218
+ for (const db of cache.databases) {
219
+ if (db.aliases.includes(normalized)) {
220
+ return db.id;
221
+ }
222
+ }
223
+ // 3. Try partial match (substring in title)
224
+ for (const db of cache.databases) {
225
+ if (db.titleNormalized.includes(normalized)) {
226
+ return db.id;
227
+ }
228
+ }
229
+ return null;
230
+ }
231
+ /**
232
+ * Search Notion API for database/page by name
233
+ *
234
+ * Uses Notion's search API as a fallback when cache lookup fails.
235
+ *
236
+ * @param query - Search query (database/page name)
237
+ * @param type - Resource type ('database' or 'page')
238
+ * @returns Database/page ID if found, null otherwise
239
+ */
240
+ async function searchNotionApi(query, type) {
241
+ try {
242
+ // Search Notion API
243
+ const response = await (0, notion_1.search)({
244
+ query,
245
+ filter: {
246
+ property: 'object',
247
+ value: type === 'database' ? 'data_source' : 'page'
248
+ },
249
+ page_size: 10
250
+ });
251
+ // Return first match
252
+ if (response && response.results && response.results.length > 0) {
253
+ return response.results[0].id;
254
+ }
255
+ return null;
256
+ }
257
+ catch {
258
+ // API search failed, return null
259
+ // The caller will throw a more helpful error message
260
+ return null;
261
+ }
262
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Notion URL Parser
3
+ *
4
+ * Extracts clean Notion IDs from various input formats:
5
+ * - Full URLs: https://www.notion.so/1fb79d4c71bb8032b722c82305b63a00?v=...
6
+ * - Short URLs: notion.so/1fb79d4c71bb8032b722c82305b63a00
7
+ * - Raw IDs with dashes: 1fb79d4c-71bb-8032-b722-c82305b63a00
8
+ * - Raw IDs without dashes: 1fb79d4c71bb8032b722c82305b63a00
9
+ */
10
+ /**
11
+ * Extract Notion ID from URL or raw ID
12
+ *
13
+ * @param input - Full Notion URL, partial URL, or raw ID
14
+ * @returns Clean Notion ID (32 hex characters without dashes)
15
+ * @throws Error if input is invalid
16
+ *
17
+ * @example
18
+ * // Full URL
19
+ * extractNotionId('https://www.notion.so/1fb79d4c71bb8032b722c82305b63a00?v=...')
20
+ * // Returns: '1fb79d4c71bb8032b722c82305b63a00'
21
+ *
22
+ * @example
23
+ * // Raw ID with dashes
24
+ * extractNotionId('1fb79d4c-71bb-8032-b722-c82305b63a00')
25
+ * // Returns: '1fb79d4c71bb8032b722c82305b63a00'
26
+ *
27
+ * @example
28
+ * // Already clean ID
29
+ * extractNotionId('1fb79d4c71bb8032b722c82305b63a00')
30
+ * // Returns: '1fb79d4c71bb8032b722c82305b63a00'
31
+ */
32
+ export declare function extractNotionId(input: string): string;
33
+ /**
34
+ * Check if a string looks like a Notion URL
35
+ *
36
+ * @param input - String to check
37
+ * @returns True if input appears to be a Notion URL
38
+ */
39
+ export declare function isNotionUrl(input: string): boolean;
40
+ /**
41
+ * Check if a string looks like a valid Notion ID
42
+ *
43
+ * @param input - String to check
44
+ * @returns True if input appears to be a valid Notion ID
45
+ */
46
+ export declare function isValidNotionId(input: string): boolean;
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ /**
3
+ * Notion URL Parser
4
+ *
5
+ * Extracts clean Notion IDs from various input formats:
6
+ * - Full URLs: https://www.notion.so/1fb79d4c71bb8032b722c82305b63a00?v=...
7
+ * - Short URLs: notion.so/1fb79d4c71bb8032b722c82305b63a00
8
+ * - Raw IDs with dashes: 1fb79d4c-71bb-8032-b722-c82305b63a00
9
+ * - Raw IDs without dashes: 1fb79d4c71bb8032b722c82305b63a00
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.extractNotionId = extractNotionId;
13
+ exports.isNotionUrl = isNotionUrl;
14
+ exports.isValidNotionId = isValidNotionId;
15
+ /**
16
+ * Extract Notion ID from URL or raw ID
17
+ *
18
+ * @param input - Full Notion URL, partial URL, or raw ID
19
+ * @returns Clean Notion ID (32 hex characters without dashes)
20
+ * @throws Error if input is invalid
21
+ *
22
+ * @example
23
+ * // Full URL
24
+ * extractNotionId('https://www.notion.so/1fb79d4c71bb8032b722c82305b63a00?v=...')
25
+ * // Returns: '1fb79d4c71bb8032b722c82305b63a00'
26
+ *
27
+ * @example
28
+ * // Raw ID with dashes
29
+ * extractNotionId('1fb79d4c-71bb-8032-b722-c82305b63a00')
30
+ * // Returns: '1fb79d4c71bb8032b722c82305b63a00'
31
+ *
32
+ * @example
33
+ * // Already clean ID
34
+ * extractNotionId('1fb79d4c71bb8032b722c82305b63a00')
35
+ * // Returns: '1fb79d4c71bb8032b722c82305b63a00'
36
+ */
37
+ function extractNotionId(input) {
38
+ if (!input || typeof input !== 'string') {
39
+ throw new Error('Input must be a non-empty string');
40
+ }
41
+ const trimmed = input.trim();
42
+ // Check if it's a URL (contains notion.so or http)
43
+ if (trimmed.includes('notion.so') || trimmed.includes('http')) {
44
+ return extractIdFromUrl(trimmed);
45
+ }
46
+ // Not a URL, treat as raw ID
47
+ return cleanRawId(trimmed);
48
+ }
49
+ /**
50
+ * Extract ID from Notion URL
51
+ */
52
+ function extractIdFromUrl(url) {
53
+ // Notion URL patterns:
54
+ // https://www.notion.so/{id}
55
+ // https://www.notion.so/{id}?v={view_id}
56
+ // https://notion.so/{id}
57
+ // www.notion.so/{id}
58
+ // Match notion.so/ followed by hex characters and optional dashes
59
+ const match = url.match(/notion\.so\/([a-f0-9-]{32,36})/i);
60
+ if (match) {
61
+ return cleanRawId(match[1]);
62
+ }
63
+ throw new Error(`Could not extract Notion ID from URL: ${url}\n\n` +
64
+ `Expected format: https://www.notion.so/{id}\n` +
65
+ `Example: https://www.notion.so/1fb79d4c71bb8032b722c82305b63a00`);
66
+ }
67
+ /**
68
+ * Clean raw ID by removing dashes and validating format
69
+ */
70
+ function cleanRawId(id) {
71
+ // Remove all dashes
72
+ const cleaned = id.replace(/-/g, '');
73
+ // Validate: must be exactly 32 hex characters
74
+ if (!/^[a-f0-9]{32}$/i.test(cleaned)) {
75
+ throw new Error(`Invalid Notion ID format: ${id}\n\n` +
76
+ `Expected: 32 hexadecimal characters (with or without dashes)\n` +
77
+ `Example: 1fb79d4c71bb8032b722c82305b63a00\n` +
78
+ `Example: 1fb79d4c-71bb-8032-b722-c82305b63a00`);
79
+ }
80
+ return cleaned.toLowerCase();
81
+ }
82
+ /**
83
+ * Check if a string looks like a Notion URL
84
+ *
85
+ * @param input - String to check
86
+ * @returns True if input appears to be a Notion URL
87
+ */
88
+ function isNotionUrl(input) {
89
+ if (!input || typeof input !== 'string') {
90
+ return false;
91
+ }
92
+ return input.includes('notion.so');
93
+ }
94
+ /**
95
+ * Check if a string looks like a valid Notion ID
96
+ *
97
+ * @param input - String to check
98
+ * @returns True if input appears to be a valid Notion ID
99
+ */
100
+ function isValidNotionId(input) {
101
+ if (!input || typeof input !== 'string') {
102
+ return false;
103
+ }
104
+ try {
105
+ extractNotionId(input);
106
+ return true;
107
+ }
108
+ catch {
109
+ return false;
110
+ }
111
+ }
@@ -0,0 +1,45 @@
1
+ import { GetDataSourceResponse } from '@notionhq/client/build/src/api-endpoints';
2
+ /**
3
+ * Simple flat property format for AI agents
4
+ * Instead of complex Notion nested structures, use simple key-value pairs:
5
+ * { "Name": "Task", "Status": "Done", "Tags": ["urgent", "bug"] }
6
+ */
7
+ export interface SimpleProperties {
8
+ [key: string]: string | number | boolean | string[] | null;
9
+ }
10
+ /**
11
+ * Notion API property format (deeply nested)
12
+ */
13
+ export interface NotionProperties {
14
+ [key: string]: any;
15
+ }
16
+ /**
17
+ * Expand simple flat properties to Notion API format
18
+ *
19
+ * This function takes simplified property values and automatically expands them
20
+ * to the correct Notion API structure based on the database schema.
21
+ *
22
+ * @param simple - Flat key-value property object
23
+ * @param schema - Database properties schema from data source
24
+ * @returns Properly formatted Notion properties object
25
+ *
26
+ * @example
27
+ * // Input (simple):
28
+ * { "Name": "My Task", "Status": "In Progress", "Priority": 5 }
29
+ *
30
+ * // Output (Notion format):
31
+ * {
32
+ * "Name": { "title": [{ "text": { "content": "My Task" } }] },
33
+ * "Status": { "select": { "name": "In Progress" } },
34
+ * "Priority": { "number": 5 }
35
+ * }
36
+ */
37
+ export declare function expandSimpleProperties(simple: SimpleProperties, schema: GetDataSourceResponse['properties']): Promise<NotionProperties>;
38
+ /**
39
+ * Validate simple properties against schema before expansion
40
+ * This can be called optionally before expandSimpleProperties to get detailed errors
41
+ */
42
+ export declare function validateSimpleProperties(simple: SimpleProperties, schema: GetDataSourceResponse['properties']): {
43
+ valid: boolean;
44
+ errors: string[];
45
+ };