or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

block-property-utilities.mdcontent-extraction.mddata-operations.mdid-url-management.mdindex.mdnavigation-structure.mdpage-analysis.mdtext-processing.md

data-operations.mddocs/

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

```