0
# Data Operations
1
2
Utilities for working with Notion's record maps, data structures, URL operations, and performing transformations on Notion's internal data formats.
3
4
## Capabilities
5
6
### Record Map Operations
7
8
Functions for manipulating and combining Notion's core data structures.
9
10
```typescript { .api }
11
/**
12
* Merges two Notion record maps into a single record map
13
* @param recordMapA - First record map
14
* @param recordMapB - Second record map (takes precedence on conflicts)
15
* @returns Combined record map with all data from both inputs
16
*/
17
function mergeRecordMaps(recordMapA: ExtendedRecordMap, recordMapB: ExtendedRecordMap): ExtendedRecordMap;
18
```
19
20
**Usage Example:**
21
22
```typescript
23
import { mergeRecordMaps } from "notion-utils";
24
25
// Merge data from multiple page fetches
26
const pageData = await getPage("page-id");
27
const additionalData = await getPage("related-page-id");
28
29
const combinedData = mergeRecordMaps(pageData, additionalData);
30
31
// Now you can access blocks from both pages
32
const allBlocks = Object.keys(combinedData.block).length;
33
console.log(`Combined data contains ${allBlocks} blocks`);
34
35
// recordMapB takes precedence for duplicate keys
36
const merged = mergeRecordMaps(
37
{ block: { "id1": { value: "old" } } },
38
{ block: { "id1": { value: "new" } } }
39
);
40
// Result: merged.block["id1"].value === "new"
41
```
42
43
### URL Operations
44
45
Advanced URL validation, normalization, and processing functions.
46
47
```typescript { .api }
48
/**
49
* Validates if a string is a valid URL
50
* @param input - String to validate
51
* @returns True if valid URL, false otherwise
52
*/
53
function isUrl(input: string): boolean;
54
55
/**
56
* Normalizes URLs for consistency (memoized for performance)
57
* @param url - URL to normalize
58
* @returns Normalized URL string or empty string if invalid
59
*/
60
function normalizeUrl(url?: string): string;
61
```
62
63
**Usage Examples:**
64
65
```typescript
66
import { isUrl, normalizeUrl } from "notion-utils";
67
68
// URL validation
69
const validUrls = [
70
"https://example.com",
71
"http://localhost:3000",
72
"ftp://files.example.com"
73
].filter(isUrl);
74
75
console.log(`Found ${validUrls.length} valid URLs`);
76
77
// URL normalization (strips protocol, www, query params, fragments)
78
const urls = [
79
"https://www.example.com/path?param=value#section",
80
"http://example.com/path/",
81
"https://example.com/path"
82
];
83
84
const normalized = urls.map(normalizeUrl);
85
// All three normalize to: "example.com/path"
86
87
// Useful for deduplication
88
const uniqueUrls = [...new Set(urls.map(normalizeUrl))];
89
console.log(`${urls.length} URLs normalized to ${uniqueUrls.length} unique URLs`);
90
```
91
92
### Image URL Processing
93
94
Functions for handling and transforming image URLs in Notion's system.
95
96
```typescript { .api }
97
/**
98
* Default function for mapping/transforming image URLs for Notion
99
* @param url - Image URL to transform
100
* @param block - Block containing the image (for context)
101
* @returns Transformed image URL or undefined to skip
102
*/
103
function defaultMapImageUrl(url: string | undefined, block: Block): string | undefined;
104
```
105
106
**Usage Examples:**
107
108
```typescript
109
import { defaultMapImageUrl } from "notion-utils";
110
111
// Transform various image URL types
112
const dataUrl = "data:image/png;base64,iVBOR...";
113
const result1 = defaultMapImageUrl(dataUrl, imageBlock);
114
// Returns: original data URL (passed through)
115
116
const unsplashUrl = "https://images.unsplash.com/photo-abc123";
117
const result2 = defaultMapImageUrl(unsplashUrl, imageBlock);
118
// Returns: original Unsplash URL (passed through)
119
120
const externalUrl = "https://example.com/image.jpg";
121
const result3 = defaultMapImageUrl(externalUrl, imageBlock);
122
// Returns: Notion-proxied URL for optimization and security
123
124
// Use with image extraction
125
import { getPageImageUrls } from "notion-utils";
126
127
const optimizedImages = getPageImageUrls(recordMap, {
128
mapImageUrl: defaultMapImageUrl
129
});
130
131
// Custom image processing
132
const customImages = getPageImageUrls(recordMap, {
133
mapImageUrl: (url, block) => {
134
const processed = defaultMapImageUrl(url, block);
135
if (processed && !processed.startsWith('data:')) {
136
// Add resize parameters
137
return `${processed}&w=800&h=600&fit=crop`;
138
}
139
return processed;
140
}
141
});
142
```
143
144
### Page URL Mapping
145
146
Functions for generating URL paths from Notion page IDs.
147
148
```typescript { .api }
149
/**
150
* Returns a function that maps page IDs to URL paths
151
* @param rootPageId - Optional root page ID that maps to '/'
152
* @returns Function that converts page IDs to URL paths
153
*/
154
function defaultMapPageUrl(rootPageId?: string): (pageId: string) => string;
155
```
156
157
**Usage Examples:**
158
159
```typescript
160
import { defaultMapPageUrl } from "notion-utils";
161
162
// Create URL mapping function
163
const mapPageUrl = defaultMapPageUrl("root-page-id-123");
164
165
// Map various page IDs to URLs
166
const homeUrl = mapPageUrl("root-page-id-123");
167
// Returns: "/"
168
169
const pageUrl = mapPageUrl("abc-123-def-456");
170
// Returns: "/abc123def456" (dashes removed)
171
172
const anotherUrl = mapPageUrl("my-blog-post-789");
173
// Returns: "/myblogpost789"
174
175
// Use in navigation generation
176
const pages = ["root-page-id-123", "about-page-456", "contact-page-789"];
177
const navigation = pages.map(pageId => ({
178
pageId,
179
url: mapPageUrl(pageId),
180
title: getPageTitle(recordMap) // Get title from your data
181
}));
182
183
console.log("Navigation:", navigation);
184
// [
185
// { pageId: "root-page-id-123", url: "/", title: "Home" },
186
// { pageId: "about-page-456", url: "/aboutpage456", title: "About" },
187
// { pageId: "contact-page-789", url: "/contactpage789", title: "Contact" }
188
// ]
189
190
// No root page specified
191
const simpleMapper = defaultMapPageUrl();
192
const url = simpleMapper("any-page-id");
193
// Returns: "/anypageid"
194
```
195
196
## Advanced Data Operations
197
198
### Record Map Structure
199
200
Understanding Notion's record map structure for advanced operations:
201
202
```typescript
203
interface ExtendedRecordMap {
204
block: Record<string, { value: Block; role: Role }>;
205
collection?: Record<string, { value: Collection; role: Role }>;
206
collection_view?: Record<string, { value: CollectionView; role: Role }>;
207
notion_user?: Record<string, { value: NotionUser; role: Role }>;
208
collection_query?: Record<string, { value: any; role: Role }>;
209
signed_urls?: Record<string, string>;
210
preview_images?: Record<string, string>;
211
}
212
213
// Each record has a value and role structure
214
interface RecordWithRole<T> {
215
value: T;
216
role: Role;
217
}
218
219
type Role = 'editor' | 'reader' | 'comment_only' | 'read_and_comment';
220
```
221
222
**Working with Record Maps:**
223
224
```typescript
225
import { mergeRecordMaps } from "notion-utils";
226
227
// Access blocks with proper typing
228
function getBlockValue(recordMap: ExtendedRecordMap, blockId: string): Block | undefined {
229
return recordMap.block[blockId]?.value;
230
}
231
232
// Merge multiple data sources
233
function combinePageData(pageMaps: ExtendedRecordMap[]): ExtendedRecordMap {
234
return pageMaps.reduce((combined, current) => {
235
return mergeRecordMaps(combined, current);
236
}, { block: {} } as ExtendedRecordMap);
237
}
238
239
// Extract all user IDs from a record map
240
function getUserIds(recordMap: ExtendedRecordMap): string[] {
241
return Object.keys(recordMap.notion_user || {});
242
}
243
244
// Get all collection IDs
245
function getCollectionIds(recordMap: ExtendedRecordMap): string[] {
246
return Object.keys(recordMap.collection || {});
247
}
248
```
249
250
## Types
251
252
```typescript { .api }
253
// Core data structure
254
interface ExtendedRecordMap {
255
block: Record<string, { value: Block; role: Role }>;
256
collection?: Record<string, { value: Collection; role: Role }>;
257
collection_view?: Record<string, { value: CollectionView; role: Role }>;
258
notion_user?: Record<string, { value: NotionUser; role: Role }>;
259
collection_query?: Record<string, { value: any; role: Role }>;
260
signed_urls?: Record<string, string>;
261
preview_images?: Record<string, string>;
262
}
263
264
interface Block {
265
id: string;
266
type: BlockType;
267
properties?: Record<string, any>;
268
format?: Record<string, any>;
269
content?: string[];
270
parent_id: string;
271
parent_table: string;
272
alive: boolean;
273
created_time: number;
274
last_edited_time: number;
275
}
276
277
type Role = 'editor' | 'reader' | 'comment_only' | 'read_and_comment';
278
279
// URL mapping function type
280
type PageUrlMapper = (pageId: string) => string;
281
282
// Image URL mapping function type
283
type ImageUrlMapper = (url: string, block: Block) => string | undefined;
284
```