astroplugin-logseq 1.1.0 → 1.1.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.
- package/README.md +98 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -1 +1,98 @@
|
|
|
1
|
-
# astroplugin-logseq
|
|
1
|
+
# astroplugin-logseq
|
|
2
|
+
  
|
|
3
|
+
|
|
4
|
+
> Turn [Logseq](https://logseq.com/) into a headless CMS for your [Astro](https://astro.build/) blog.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
This plugin creates a synchronization bridge between a local Logseq graph and Astro Content Collections.
|
|
9
|
+
|
|
10
|
+
It operates by polling the Logseq HTTP API for pages containing specific tags and writing them as Markdown files to defined directories within an Astro project. This allows a Logseq graph to function as a content source for static site generation without manual export steps.
|
|
11
|
+
|
|
12
|
+
## Functionality
|
|
13
|
+
* **API Polling:** Connects to the local Logseq HTTP API to retrieve page content.
|
|
14
|
+
* **Selective Sync:** Filters pages based on user-defined tags (e.g., `blog`, `notes`) and maps them to specific target directories.
|
|
15
|
+
* **Block Preservation:** Maintains the hierarchy of Logseq blocks, rendering them as nested lists in the output Markdown.
|
|
16
|
+
* **Change Detection:** Compares fetched content against existing files on disk to minimize unnecessary write operations.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
npm install astroplugin-logseq
|
|
20
|
+
|
|
21
|
+
## Configuration
|
|
22
|
+
### 1. Enable Logseq HTTP API
|
|
23
|
+
For this plugin to function, the Logseq HTTP API must be active:
|
|
24
|
+
|
|
25
|
+
1. Navigate to **Settings** > **Features** in Logseq.
|
|
26
|
+
2. Enable **HTTP API Server**.
|
|
27
|
+
3. In the **Authorization tokens** section, generate a new token.
|
|
28
|
+
|
|
29
|
+
### 2. Integration Setup
|
|
30
|
+
Add the integration to `astro.config.mjs`. The configuration accepts a `targets` array to map specific Logseq tags to corresponding file system paths.
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { defineConfig } from 'astro/config';
|
|
34
|
+
import logseq from 'astroplugin-logseq';
|
|
35
|
+
|
|
36
|
+
export default defineConfig({
|
|
37
|
+
integrations: [
|
|
38
|
+
logseq({
|
|
39
|
+
// Required: The authorization token generated in Logseq
|
|
40
|
+
token: 'YOUR_SECRET_LOGSEQ_TOKEN',
|
|
41
|
+
|
|
42
|
+
// Required: mapping tags to destination directories
|
|
43
|
+
targets: [
|
|
44
|
+
{
|
|
45
|
+
tag: 'blog',
|
|
46
|
+
directory: 'src/content/blog'
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
tag: 'notes',
|
|
50
|
+
directory: 'src/content/notes'
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
|
|
54
|
+
// Optional: API URL (defaults to http://127.0.0.1:12315/api)
|
|
55
|
+
apiUrl: 'http://127.0.0.1:12315/api',
|
|
56
|
+
|
|
57
|
+
// Optional: Polling interval in ms (defaults to 500)
|
|
58
|
+
pollingInterval: 1000,
|
|
59
|
+
})
|
|
60
|
+
],
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 3. Usage
|
|
65
|
+
Once configured, the plugin will poll the API when the Astro development server is running (`npm run dev`).
|
|
66
|
+
|
|
67
|
+
To trigger a sync for a specific page, add the configured tag to the page properties or body in Logseq:
|
|
68
|
+
|
|
69
|
+
## Metadata Handling
|
|
70
|
+
The plugin currently generates Frontmatter based on the available system data from the Logseq API:
|
|
71
|
+
|
|
72
|
+
* **Title:** Mapped from the Logseq Page Title.
|
|
73
|
+
* **Date:** Mapped from the Logseq `created-at` timestamp.
|
|
74
|
+
|
|
75
|
+
*Note: The ability to override the date via custom page properties is not yet implemented.*
|
|
76
|
+
|
|
77
|
+
**Output Example:**
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
title: "Project Documentation"
|
|
81
|
+
date: 1767755762522
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
Primary block content.
|
|
85
|
+
|
|
86
|
+
- Child block 1
|
|
87
|
+
- Child block 2
|
|
88
|
+
- Grandchild block
|
|
89
|
+
|
|
90
|
+
## ☕️ Support
|
|
91
|
+
If you enjoy this plugin, please consider supporting the development!
|
|
92
|
+
|
|
93
|
+
<div align="center">
|
|
94
|
+
<a href="https://github.com/sponsors/benjypng"><img src="https://img.shields.io/badge/Sponsor-GitHub-ea4aaa?style=for-the-badge&logo=github" alt="Sponsor on Github" /></a> <a href="https://www.buymeacoffee.com/hkgnp.dev"><img src="https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black" alt="Buy Me a Coffee" /></a>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
MIT
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/utils/has-content-changed.ts","../src/utils/process-tag-group.ts","../src/api/get-page-blocks-tree.ts","../src/api/get-raw-response.ts","../src/utils/recursively-get-content.ts","../src/utils/write-to-md.ts","../src/utils/get-clean-slug.ts"],"sourcesContent":["import { AstroIntegration } from 'astro'\nimport wretch from 'wretch'\n\nimport { LogseqIntegrationOptions } from './types'\nimport { processTagGroup } from './utils'\n\nexport default function logseqIntegration(\n options: LogseqIntegrationOptions,\n): AstroIntegration {\n const {\n token,\n targets,\n apiUrl = 'http://127.0.0.1:12315/api',\n pollingInterval = 1000,\n } = options\n\n return {\n name: 'astro-logseq-publish',\n hooks: {\n 'astro:server:setup': ({ logger }) => {\n logger.info('🚀 Logseq Poller Started (Every 3s)')\n\n const api = wretch()\n .url(apiUrl)\n .headers({\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n })\n\n setInterval(async () => {\n try {\n await Promise.all(\n targets.map((target) => processTagGroup(api, target, logger)),\n )\n } catch (e: any) {\n logger.error(e.message || String(e))\n }\n }, pollingInterval)\n },\n 'astro:build:setup': async ({ logger }) => {\n logger.info('Building from Logseq...')\n },\n },\n }\n}\n","import fs from \"node:fs/promises\";\n\nexport const hasContentChanged = async (path: string, newContent: string) => {\n try {\n const currentContent = await fs.readFile(path, \"utf-8\");\n return currentContent !== newContent;\n } catch {\n return true;\n }\n};\n","import { format } from 'date-fns'\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/utils/has-content-changed.ts","../src/utils/process-tag-group.ts","../src/api/get-page-blocks-tree.ts","../src/api/get-raw-response.ts","../src/utils/recursively-get-content.ts","../src/utils/write-to-md.ts","../src/utils/get-clean-slug.ts"],"sourcesContent":["import { AstroIntegration } from 'astro'\nimport wretch from 'wretch'\n\nimport { LogseqIntegrationOptions } from './types'\nimport { processTagGroup } from './utils'\n\nexport default function logseqIntegration(\n options: LogseqIntegrationOptions,\n): AstroIntegration {\n const {\n token,\n targets,\n apiUrl = 'http://127.0.0.1:12315/api',\n pollingInterval = 1000,\n } = options\n\n return {\n name: 'astro-logseq-publish',\n hooks: {\n 'astro:server:setup': ({ logger }) => {\n logger.info('🚀 Logseq Poller Started (Every 3s)')\n\n const api = wretch()\n .url(apiUrl)\n .headers({\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n })\n\n setInterval(async () => {\n try {\n await Promise.all(\n targets.map((target) => processTagGroup(api, target, logger)),\n )\n } catch (e: any) {\n logger.error(e.message || String(e))\n }\n }, pollingInterval)\n },\n 'astro:build:setup': async ({ logger }) => {\n logger.info('Building from Logseq...')\n },\n },\n }\n}\n","import fs from \"node:fs/promises\";\n\nexport const hasContentChanged = async (path: string, newContent: string) => {\n try {\n const currentContent = await fs.readFile(path, \"utf-8\");\n return currentContent !== newContent;\n } catch {\n return true;\n }\n};\n","import { format } from 'date-fns'\nimport { Wretch } from 'wretch/types'\n\nimport { getPageBlocksTree, getRawResponse } from '../api'\nimport { MappedResponse, TagTarget } from '../types'\nimport { recursivelyGetContent, writeToMd } from '.'\n\nexport const processTagGroup = async (\n api: Wretch,\n target: TagTarget,\n logger: any,\n) => {\n const { tag, directory } = target\n\n const rawResponse = await getRawResponse(api, tag, logger)\n if (!rawResponse || rawResponse.length === 0) return\n\n const mappedResponse: MappedResponse[] = []\n\n for (const item of rawResponse.flat()) {\n const pbt = await getPageBlocksTree(api, item, logger)\n if (!pbt) continue\n\n mappedResponse.push({\n createdAt: format(item['created-at'], 'yyyy-MM-dd'),\n updatedAt: format(item['updated-at'], 'yyyy-MM-dd'),\n pageTitle: item.title,\n content: recursivelyGetContent(pbt),\n })\n }\n\n await writeToMd(directory, mappedResponse, logger)\n}\n","import { AstroIntegrationLogger } from 'astro'\nimport { Wretch } from 'wretch/types'\n\nimport { ContentBlock, LogseqResponse } from '../types'\n\nexport const getPageBlocksTree = async (\n api: Wretch,\n item: LogseqResponse,\n logger: AstroIntegrationLogger,\n) => {\n try {\n return await api\n .post({\n method: 'logseq.Editor.getPageBlocksTree',\n args: [item.title.toLowerCase()],\n })\n .json<ContentBlock[]>()\n } catch (e) {\n logger.info(`Unable to get page blocks tree: ${String(e)}`)\n }\n}\n","import { AstroIntegrationLogger } from 'astro'\nimport { Wretch } from 'wretch/types'\n\nimport { LogseqResponse } from '../types'\n\nexport const getRawResponse = async (\n api: Wretch,\n tag: string,\n logger: AstroIntegrationLogger,\n) => {\n const query = `\n [:find (pull ?p\n [:block/name\n :block/full-title\n :block/created-at\n :block/updated-at\n :block/title\n {:block/_parent ...}])\n :where\n [?p :block/name]\n [?p :block/tags ?t]\n [?t :block/name \"${tag}\"]]`\n\n try {\n return (\n (await api\n .post({\n method: 'logseq.DB.datascriptQuery',\n args: [query],\n })\n .json<LogseqResponse[][]>()) ?? []\n )\n } catch (e) {\n logger.info(\n `Unable to query Logseq. Check if API server is running. ${String(e)}`,\n )\n }\n}\n","import { ContentBlock } from \"../types\";\n\nexport const recursivelyGetContent = (\n contentBlocks: ContentBlock[],\n depth = 0,\n) => {\n let content = \"\";\n const indent = \" \".repeat(depth);\n for (const block of contentBlocks) {\n const text = block.title || \"\";\n if (depth === 0) {\n content += `\\n\\n${text}`;\n } else {\n content += `\\n${indent}- ${text}`;\n }\n if (block.children && block.children.length > 0) {\n content += recursivelyGetContent(block.children, depth + 1);\n }\n }\n return content;\n};\n","import fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport { AstroIntegrationLogger } from 'astro'\n\nimport { MappedResponse } from '../types'\nimport { hasContentChanged } from '.'\nimport { getCleanSlug } from './get-clean-slug'\n\nexport const writeToMd = async (\n directory: string,\n mappedResponse: MappedResponse[],\n logger: AstroIntegrationLogger,\n) => {\n const targetDir = path.resolve(process.cwd(), directory)\n\n try {\n await fs.mkdir(targetDir, { recursive: true })\n await Promise.all(\n mappedResponse.map(async (page) => {\n const cleanSlug = getCleanSlug(page)\n const filePath = path.join(targetDir, `${cleanSlug}.md`)\n const fileContent = `---\ntitle: ${page.pageTitle}\ndate: ${page.createdAt}\n---\n${page.content}`\n const contentToSave = fileContent.trim()\n if (await hasContentChanged(filePath, contentToSave)) {\n await fs.writeFile(filePath, contentToSave, 'utf-8')\n }\n }),\n )\n } catch (e) {\n logger.info(`Unable to create MD files: ${String(e)}`)\n }\n}\n","import { MappedResponse } from '../types'\n\nexport const getCleanSlug = (page: MappedResponse) =>\n page.pageTitle\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/(^-|-$)/g, '')\n"],"mappings":"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","names":["path","fs","import_promises","path","fs","wretch"]}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/utils/has-content-changed.ts","../src/utils/process-tag-group.ts","../src/api/get-page-blocks-tree.ts","../src/api/get-raw-response.ts","../src/utils/recursively-get-content.ts","../src/utils/write-to-md.ts","../src/utils/get-clean-slug.ts"],"sourcesContent":["import { AstroIntegration } from 'astro'\nimport wretch from 'wretch'\n\nimport { LogseqIntegrationOptions } from './types'\nimport { processTagGroup } from './utils'\n\nexport default function logseqIntegration(\n options: LogseqIntegrationOptions,\n): AstroIntegration {\n const {\n token,\n targets,\n apiUrl = 'http://127.0.0.1:12315/api',\n pollingInterval = 1000,\n } = options\n\n return {\n name: 'astro-logseq-publish',\n hooks: {\n 'astro:server:setup': ({ logger }) => {\n logger.info('🚀 Logseq Poller Started (Every 3s)')\n\n const api = wretch()\n .url(apiUrl)\n .headers({\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n })\n\n setInterval(async () => {\n try {\n await Promise.all(\n targets.map((target) => processTagGroup(api, target, logger)),\n )\n } catch (e: any) {\n logger.error(e.message || String(e))\n }\n }, pollingInterval)\n },\n 'astro:build:setup': async ({ logger }) => {\n logger.info('Building from Logseq...')\n },\n },\n }\n}\n","import fs from \"node:fs/promises\";\n\nexport const hasContentChanged = async (path: string, newContent: string) => {\n try {\n const currentContent = await fs.readFile(path, \"utf-8\");\n return currentContent !== newContent;\n } catch {\n return true;\n }\n};\n","import { format } from 'date-fns'\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/utils/has-content-changed.ts","../src/utils/process-tag-group.ts","../src/api/get-page-blocks-tree.ts","../src/api/get-raw-response.ts","../src/utils/recursively-get-content.ts","../src/utils/write-to-md.ts","../src/utils/get-clean-slug.ts"],"sourcesContent":["import { AstroIntegration } from 'astro'\nimport wretch from 'wretch'\n\nimport { LogseqIntegrationOptions } from './types'\nimport { processTagGroup } from './utils'\n\nexport default function logseqIntegration(\n options: LogseqIntegrationOptions,\n): AstroIntegration {\n const {\n token,\n targets,\n apiUrl = 'http://127.0.0.1:12315/api',\n pollingInterval = 1000,\n } = options\n\n return {\n name: 'astro-logseq-publish',\n hooks: {\n 'astro:server:setup': ({ logger }) => {\n logger.info('🚀 Logseq Poller Started (Every 3s)')\n\n const api = wretch()\n .url(apiUrl)\n .headers({\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n })\n\n setInterval(async () => {\n try {\n await Promise.all(\n targets.map((target) => processTagGroup(api, target, logger)),\n )\n } catch (e: any) {\n logger.error(e.message || String(e))\n }\n }, pollingInterval)\n },\n 'astro:build:setup': async ({ logger }) => {\n logger.info('Building from Logseq...')\n },\n },\n }\n}\n","import fs from \"node:fs/promises\";\n\nexport const hasContentChanged = async (path: string, newContent: string) => {\n try {\n const currentContent = await fs.readFile(path, \"utf-8\");\n return currentContent !== newContent;\n } catch {\n return true;\n }\n};\n","import { format } from 'date-fns'\nimport { Wretch } from 'wretch/types'\n\nimport { getPageBlocksTree, getRawResponse } from '../api'\nimport { MappedResponse, TagTarget } from '../types'\nimport { recursivelyGetContent, writeToMd } from '.'\n\nexport const processTagGroup = async (\n api: Wretch,\n target: TagTarget,\n logger: any,\n) => {\n const { tag, directory } = target\n\n const rawResponse = await getRawResponse(api, tag, logger)\n if (!rawResponse || rawResponse.length === 0) return\n\n const mappedResponse: MappedResponse[] = []\n\n for (const item of rawResponse.flat()) {\n const pbt = await getPageBlocksTree(api, item, logger)\n if (!pbt) continue\n\n mappedResponse.push({\n createdAt: format(item['created-at'], 'yyyy-MM-dd'),\n updatedAt: format(item['updated-at'], 'yyyy-MM-dd'),\n pageTitle: item.title,\n content: recursivelyGetContent(pbt),\n })\n }\n\n await writeToMd(directory, mappedResponse, logger)\n}\n","import { AstroIntegrationLogger } from 'astro'\nimport { Wretch } from 'wretch/types'\n\nimport { ContentBlock, LogseqResponse } from '../types'\n\nexport const getPageBlocksTree = async (\n api: Wretch,\n item: LogseqResponse,\n logger: AstroIntegrationLogger,\n) => {\n try {\n return await api\n .post({\n method: 'logseq.Editor.getPageBlocksTree',\n args: [item.title.toLowerCase()],\n })\n .json<ContentBlock[]>()\n } catch (e) {\n logger.info(`Unable to get page blocks tree: ${String(e)}`)\n }\n}\n","import { AstroIntegrationLogger } from 'astro'\nimport { Wretch } from 'wretch/types'\n\nimport { LogseqResponse } from '../types'\n\nexport const getRawResponse = async (\n api: Wretch,\n tag: string,\n logger: AstroIntegrationLogger,\n) => {\n const query = `\n [:find (pull ?p\n [:block/name\n :block/full-title\n :block/created-at\n :block/updated-at\n :block/title\n {:block/_parent ...}])\n :where\n [?p :block/name]\n [?p :block/tags ?t]\n [?t :block/name \"${tag}\"]]`\n\n try {\n return (\n (await api\n .post({\n method: 'logseq.DB.datascriptQuery',\n args: [query],\n })\n .json<LogseqResponse[][]>()) ?? []\n )\n } catch (e) {\n logger.info(\n `Unable to query Logseq. Check if API server is running. ${String(e)}`,\n )\n }\n}\n","import { ContentBlock } from \"../types\";\n\nexport const recursivelyGetContent = (\n contentBlocks: ContentBlock[],\n depth = 0,\n) => {\n let content = \"\";\n const indent = \" \".repeat(depth);\n for (const block of contentBlocks) {\n const text = block.title || \"\";\n if (depth === 0) {\n content += `\\n\\n${text}`;\n } else {\n content += `\\n${indent}- ${text}`;\n }\n if (block.children && block.children.length > 0) {\n content += recursivelyGetContent(block.children, depth + 1);\n }\n }\n return content;\n};\n","import fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport { AstroIntegrationLogger } from 'astro'\n\nimport { MappedResponse } from '../types'\nimport { hasContentChanged } from '.'\nimport { getCleanSlug } from './get-clean-slug'\n\nexport const writeToMd = async (\n directory: string,\n mappedResponse: MappedResponse[],\n logger: AstroIntegrationLogger,\n) => {\n const targetDir = path.resolve(process.cwd(), directory)\n\n try {\n await fs.mkdir(targetDir, { recursive: true })\n await Promise.all(\n mappedResponse.map(async (page) => {\n const cleanSlug = getCleanSlug(page)\n const filePath = path.join(targetDir, `${cleanSlug}.md`)\n const fileContent = `---\ntitle: ${page.pageTitle}\ndate: ${page.createdAt}\n---\n${page.content}`\n const contentToSave = fileContent.trim()\n if (await hasContentChanged(filePath, contentToSave)) {\n await fs.writeFile(filePath, contentToSave, 'utf-8')\n }\n }),\n )\n } catch (e) {\n logger.info(`Unable to create MD files: ${String(e)}`)\n }\n}\n","import { MappedResponse } from '../types'\n\nexport const getCleanSlug = (page: MappedResponse) =>\n page.pageTitle\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/(^-|-$)/g, '')\n"],"mappings":"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","names":["path","fs","fs"]}
|
package/package.json
CHANGED
|
@@ -28,11 +28,14 @@
|
|
|
28
28
|
"scripts": {
|
|
29
29
|
"build": "tsup",
|
|
30
30
|
"dev": "tsup --watch",
|
|
31
|
-
"prepublishOnly": "npm run build"
|
|
31
|
+
"prepublishOnly": "npm run build",
|
|
32
|
+
"prepare": "command -v husky >/dev/null && husky || true",
|
|
33
|
+
"lint:precommit": "echo \"Running eslint\" && npx eslint . --fix && echo \"Running tsc\" && tsc && echo \"Running build\" && bun run build"
|
|
32
34
|
},
|
|
33
35
|
"publishConfig": {
|
|
34
36
|
"access": "public",
|
|
35
|
-
"registry": "https://registry.npmjs.org/"
|
|
37
|
+
"registry": "https://registry.npmjs.org/",
|
|
38
|
+
"provenance": true
|
|
36
39
|
},
|
|
37
40
|
"release": {
|
|
38
41
|
"branches": [
|
|
@@ -70,5 +73,5 @@
|
|
|
70
73
|
"typescript": "^5.5.4",
|
|
71
74
|
"typescript-eslint": "^8.51.0"
|
|
72
75
|
},
|
|
73
|
-
"version": "1.1.
|
|
76
|
+
"version": "1.1.1"
|
|
74
77
|
}
|