Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Refactored with [Turboplate](https://github.com/seonglae/turboplate). Search API

```zsh
pnpm i
pnpm build # TSUp
pnpm build # Vite
pnpm test # Vitest
```

Expand Down Expand Up @@ -58,7 +58,7 @@ pnpm turbo pu
[Turboplate](https://github.com/seonglae/turboplate) stacks

- `Turborepo` monorepo
- `TSup` build
- `Vite` build
- `Vitest` test
- `ESLint` lint
- `Prettier` format
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@
"husky": "^9.1.7",
"prettier": "^3.5.3",
"standard-version": "^9.5.0",
"tsup": "^8.5.0",
"tsx": "^4.19.4",
"turbo": "^2.5.4",
"typescript": "^5.8.3",
"vite": "^6.3.5",
"vite-plugin-dts": "^3.8.1",
"vitest": "^3.2.2"
},
"standard-version": {
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
"notion": "./build/src/main.js"
},
"scripts": {
"build": "tsc && tsup",
"watch": "tsup --watch --silent --onSuccess 'echo build successful'",
"build": "tsc && vite build",
"watch": "vite build --watch --mode development",
"test": "vitest --run",
"prerelease": "standard-version --skip.changelog --prerelease",
"release": "standard-version --release-as",
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ export * from './notion/export'
export * from './notion/index'
export * from './treemap'
export * from './stats'
export * from './treemap'
export * from './stats'
Comment on lines +21 to +22
Copy link
Preview

Copilot AI Jun 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The duplicate export statement for './treemap' (and similarly for './stats') can cause redundancy and potential conflicts. Remove the extra export lines to keep the module exports clear.

Suggested change
export * from './treemap'
export * from './stats'

Copilot uses AI. Check for mistakes.

18 changes: 18 additions & 0 deletions packages/cli/src/notion/export.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
import { Option, Command } from 'clipanion'
import { NotionExporter } from './index'
import { generateTreemaps, PageNode } from '../treemap'
import { computeStats, writeStats } from '../stats'
treemap = Option.Boolean('--treemap', {
description: 'Generate HTML treemap after export'
})
stats = Option.Boolean('--stats', {
description: 'Generate statistics JSON after export'
})

if (this.treemap || this.stats) if (!exporter.pageTree) await exporter.loadRaw()

const tree = exporter.pageTree as unknown as PageNode
if (this.treemap && tree) await generateTreemaps(this.folder, tree)

if (this.stats && tree) {
const stats = computeStats(tree)
await writeStats(`${this.folder}/stats.json`, stats)
}
import { generateTreemaps, PageNode } from '../treemap'
Copy link
Preview

Copilot AI Jun 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A duplicate import of 'generateTreemaps' and 'PageNode' was introduced, which can lead to confusion and potential maintenance issues. Removing the redundant import should resolve this.

Suggested change
import { generateTreemaps, PageNode } from '../treemap'

Copilot uses AI. Check for mistakes.

import { computeStats, writeStats } from '../stats'

export class NotionExportCommand extends Command {
Expand Down
7 changes: 0 additions & 7 deletions packages/cli/src/treemap.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,21 @@
import fs from 'fs'
import { promisify } from 'util'

export interface PageNode {
id: string
blocks: number
pages: number
title: string
children?: PageNode[]
}

const writeFile = promisify(fs.writeFile)

export async function generateTreemaps(folder: string, pageTree: PageNode) {
const treemapDataPages = computeMetrics(pageTree, 'pages')
const titlePages = 'Texonom PageTree'
const outputPathPages = `${folder}/pagetree.html`
await generateTreemapHTML(treemapDataPages, titlePages, outputPathPages)

const treemapDataBlocks = computeMetrics(pageTree, 'blocks')
const titleBlocks = 'Texonom BlockMap'
const outputPathBlocks = `${folder}/blocktree.html`
await generateTreemapHTML(treemapDataBlocks, titleBlocks, outputPathBlocks)
}

interface TreemapNode {
id: string
name: string
Expand Down
14 changes: 0 additions & 14 deletions packages/cli/tsup.config.ts

This file was deleted.

30 changes: 30 additions & 0 deletions packages/cli/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { defineConfig } from 'vite'
import dts from 'vite-plugin-dts'
import pkg from './package.json' assert { type: 'json' }

export default defineConfig({
build: {
lib: {
entry: 'src/main.ts',
formats: ['es'],
fileName: () => 'main.js'
},
outDir: 'build/src',
target: 'node16',
sourcemap: true,
minify: true,
rollupOptions: {
external: [
...Object.keys(pkg.dependencies || {}),
...Object.keys(pkg.peerDependencies || {}),
'fs',
'fs/promises',
'path',
'stream',
'util'
]
}
},
plugins: [dts({ tsconfigPath: 'tsconfig.json', outDir: 'build/src' })]
})

4 changes: 2 additions & 2 deletions packages/nclient/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
"node": ">=22.16.0"
},
"scripts": {
"build": "tsc && tsup",
"watch": "tsup --watch --silent --onSuccess 'echo build successful'",
"build": "tsc && vite build",
"watch": "vite build --watch --mode development",
"test": "vitest --run",
"prerelease": "standard-version --skip.changelog --prerelease",
"release": "standard-version --release-as",
Expand Down
13 changes: 13 additions & 0 deletions packages/nclient/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,19 @@ const backlinks = await api.getBacklinks({
const pageBacklinks = await api.getPageBacklinks('page-id')
```

### Fetch backlinks

Backlinks require an auth token.

```ts
const backlinks = await api.getBacklinks({
block: { id: 'page-id', spaceId: 'space-id' }
})

// or simply pass the page id
const pageBacklinks = await api.getPageBacklinks('page-id')
```

### Fetch a database's content

You can pass a database ID to the `getPage` method. The response is an object which contains several important properties:
Expand Down
6 changes: 6 additions & 0 deletions packages/nclient/src/notion-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ test(`Page Backlink`, { timeout: 10000, concurrent: true }, async () => {
expect(backlinks.backlinks.length > 0)
})

test(`Page Backlink`, { timeout: 10000, concurrent: true }, async () => {
const api = new NotionAPI({ authToken: process.env.NOTION_TOKEN })
const backlinks = await api.getPageBacklinks('441d5ce2-b781-46d0-9354-54042b4f06d9')
expect(backlinks.backlinks.length > 0)
})

test(`Get block`, { timeout: 10000, concurrent: true }, async () => {
const id = '3f9e0d86-c643-4672-aa0c-78d63fa80598'
const api = new NotionAPI()
Expand Down
17 changes: 17 additions & 0 deletions packages/nclient/src/notion-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,23 @@ export class NotionAPI {
return this.getBacklinks({ block: { id, spaceId } }, fetchOption)
}

/**
* Fetch backlinks for a page by automatically resolving its space id.
* Requires an authToken since backlinks are a private API.
*
* @param pageId page id or url
* @param fetchOption additional fetch options
*/
public async getPageBacklinks(pageId: string, fetchOption?: FetchOption) {
const id = parsePageId(pageId)
const res = await this.getBlocks([id], fetchOption)
const block = res.recordMap.block[id]?.value
if (!block) throw new Error(`Block not found "${uuidToId(id)}"`)
const spaceId = block.space_id

return this.getBacklinks({ block: { id, spaceId } }, fetchOption)
}

public async fetch<T>({
endpoint,
body,
Expand Down
14 changes: 0 additions & 14 deletions packages/nclient/tsup.config.ts

This file was deleted.

21 changes: 21 additions & 0 deletions packages/nclient/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { defineConfig } from 'vite'
import dts from 'vite-plugin-dts'
import pkg from './package.json' assert { type: 'json' }

export default defineConfig({
build: {
lib: {
entry: 'src/index.ts',
formats: ['es'],
fileName: () => 'index.js'
},
outDir: 'build',
target: 'es2015',
sourcemap: true,
minify: true,
rollupOptions: {
external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})]
}
},
plugins: [dts({ tsconfigPath: 'tsconfig.json', outDir: 'build' })]
})
4 changes: 2 additions & 2 deletions packages/ncompat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
"node": ">=22.16.0"
},
"scripts": {
"build": "tsc && tsup",
"watch": "tsup --watch --silent --onSuccess 'echo build successful'",
"build": "tsc && vite build",
"watch": "vite build --watch --mode development",
"prerelease": "standard-version --skip.changelog --prerelease",
"release": "standard-version --release-as",
"pu": "pnpm publish"
Expand Down
13 changes: 0 additions & 13 deletions packages/ncompat/tsup.config.ts

This file was deleted.

21 changes: 21 additions & 0 deletions packages/ncompat/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { defineConfig } from 'vite'
import dts from 'vite-plugin-dts'
import pkg from './package.json' assert { type: 'json' }

export default defineConfig({
build: {
lib: {
entry: 'src/index.ts',
formats: ['es'],
fileName: () => 'index.js'
},
outDir: 'build',
target: 'es2015',
sourcemap: true,
minify: true,
rollupOptions: {
external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})]
}
},
plugins: [dts({ tsconfigPath: 'tsconfig.json', outDir: 'build' })]
})
4 changes: 2 additions & 2 deletions packages/nreact/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
"node": ">=22.16.0"
},
"scripts": {
"build": "tsc && tsup",
"watch": "tsup --watch --silent --onSuccess 'echo build successful'",
"build": "tsc && vite build",
"watch": "vite build --watch --mode development",
"prerelease": "standard-version --skip.changelog --prerelease",
"release": "standard-version --release-as",
"pu": "pnpm publish"
Expand Down
12 changes: 10 additions & 2 deletions packages/nreact/src/components/search-dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import React from 'react'
import { getBlockParentPage, getBlockTitle } from '@texonom/nutils'

import { NotionContextConsumer, NotionContextProvider } from '../context'
import { ClearIcon } from '../icons/clear-icon'
import { LoadingIcon } from '../icons/loading-icon'
Expand All @@ -19,6 +17,16 @@ const debounce = (func: (...args: any[]) => void, wait: number) => {
}
}

// debounce search calls so the expensive query only runs after typing stops
this._search = debounce(this._searchImpl.bind(this), 500)
onInput={this._onChangeQuery}
Copy link
Preview

Copilot AI Jun 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'onInput={this._onChangeQuery}' attribute appears to be misplaced within the debounce function block. Consider moving it to the appropriate component JSX element to avoid unintended behavior.

Copilot uses AI. Check for mistakes.

let timeout: ReturnType<typeof setTimeout> | undefined
return (...args: any[]) => {
if (timeout) clearTimeout(timeout)
timeout = setTimeout(() => func(...args), wait)
}
}

export class SearchDialog extends React.Component<{
isOpen: boolean
rootBlockId: string
Expand Down
7 changes: 6 additions & 1 deletion packages/nreact/src/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,15 @@ export const NotionContextProvider: React.FC<PartialNotionContext> = ({
if (components.nextLink) {
const nextLink = wrapNextLink(components.nextLink)
components.nextLink = nextLink

if (!components.PageLink) components.PageLink = nextLink
if (!components.Link) components.Link = nextLink
}
// ensure the user can't override default components with falsy values
// since it would result in very difficult-to-debug react errors
for (const key of Object.keys(components)) if (!components[key]) delete components[key]

return components
}, [themeComponents])

// ensure the user can't override default components with falsy values
// since it would result in very difficult-to-debug react errors
Expand Down
34 changes: 0 additions & 34 deletions packages/nreact/tsup.config.ts

This file was deleted.

Loading
Loading