@jordancoin/notioncli 1.2.0 → 1.3.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.
- package/README.md +111 -423
- package/TECHNICAL.md +125 -0
- package/bin/notion.js +925 -814
- package/lib/config.js +68 -0
- package/lib/filters.js +213 -0
- package/lib/format.js +225 -0
- package/lib/helpers.js +9 -334
- package/lib/markdown.js +347 -0
- package/package.json +1 -1
- package/skill/SKILL.md +44 -10
- package/skill/marketplace.json +2 -2
- package/test/unit.test.js +392 -0
- package/test/debug-parent.js +0 -32
- package/test/live-relations-test.js +0 -309
package/TECHNICAL.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Technical Notes
|
|
2
|
+
|
|
3
|
+
Deep dive into how notioncli works under the hood. You don't need any of this to use the CLI — it just works. This is for contributors and the curious.
|
|
4
|
+
|
|
5
|
+
## Notion API 2025-09-03 — Dual ID System
|
|
6
|
+
|
|
7
|
+
The 2025 API introduced a dual-ID system for databases:
|
|
8
|
+
|
|
9
|
+
| ID | What it's for | Example endpoint |
|
|
10
|
+
|----|---------------|-----------------|
|
|
11
|
+
| `database_id` | Page creation (`parent`), `databases.retrieve()` | `pages.create({ parent: { database_id } })` |
|
|
12
|
+
| `data_source_id` | Querying, schema, property management | `dataSources.query()`, `dataSources.retrieve()`, `dataSources.update()` |
|
|
13
|
+
|
|
14
|
+
When you run `notion init`, both IDs are discovered and stored per alias. When you pass a raw UUID, notioncli resolves which ID to use depending on the operation.
|
|
15
|
+
|
|
16
|
+
### The Silent Data Loss Bug
|
|
17
|
+
|
|
18
|
+
`databases.update()` silently ignores property changes in the 2025 API. It returns `200 OK` but drops all property modifications. You must use `dataSources.update()` for:
|
|
19
|
+
|
|
20
|
+
- Adding properties
|
|
21
|
+
- Removing properties
|
|
22
|
+
- Renaming properties
|
|
23
|
+
|
|
24
|
+
`databases.update()` still works for title changes only.
|
|
25
|
+
|
|
26
|
+
Similarly, `databases.create()` silently ignores non-title properties. notioncli handles this with a two-step approach:
|
|
27
|
+
|
|
28
|
+
1. Create the database with title via `databases.create()`
|
|
29
|
+
2. Add properties via `dataSources.update()`
|
|
30
|
+
|
|
31
|
+
### Where Schema Lives
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
databases.retrieve(database_id) → NO properties field
|
|
35
|
+
dataSources.retrieve(data_source_id) → HAS properties field (this is the schema)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`getDbSchema()` in notioncli correctly uses `dataSources.retrieve()`.
|
|
39
|
+
|
|
40
|
+
### dataSources Methods
|
|
41
|
+
|
|
42
|
+
The `dataSources` namespace provides: `retrieve`, `query`, `create`, `update`, `listTemplates`.
|
|
43
|
+
|
|
44
|
+
## Architecture
|
|
45
|
+
|
|
46
|
+
### Alias Resolution
|
|
47
|
+
|
|
48
|
+
Every command that targets a database goes through `resolveDb(alias_or_id)`:
|
|
49
|
+
|
|
50
|
+
1. Check aliases in config (scoped to active workspace)
|
|
51
|
+
2. If UUID, return as-is (used as `data_source_id`)
|
|
52
|
+
3. If neither, error with helpful suggestion
|
|
53
|
+
|
|
54
|
+
### Filter → Page Resolution
|
|
55
|
+
|
|
56
|
+
Commands that target a single page (update, delete, get, etc.) use `resolvePageId()`:
|
|
57
|
+
|
|
58
|
+
1. If input is a UUID → return directly
|
|
59
|
+
2. If input is an alias → require `--filter`, query the database, expect exactly 1 result
|
|
60
|
+
3. Zero matches → error with "No pages found"
|
|
61
|
+
4. Multiple matches → error with "Multiple pages found, refine your filter"
|
|
62
|
+
|
|
63
|
+
### Dynamic Property Flags (v1.3+)
|
|
64
|
+
|
|
65
|
+
Commander.js `.allowUnknownOption()` lets unknown flags pass through. `extractDynamicProps()` parses raw `process.argv`:
|
|
66
|
+
|
|
67
|
+
1. Find flags starting with `--` that aren't in the known flags list
|
|
68
|
+
2. Convert `--kebab-case` to `Title Case` via `kebabToProperty()`
|
|
69
|
+
3. Match against database schema (case-insensitive)
|
|
70
|
+
4. Return as `Key=Value` pairs for property building
|
|
71
|
+
|
|
72
|
+
### Rich Filter Operators (v1.3+)
|
|
73
|
+
|
|
74
|
+
`parseFilterOperator()` splits filter strings by checking operators in order: `>=`, `<=`, `!=`, `>`, `<`, `=` (multi-char first to avoid false splits).
|
|
75
|
+
|
|
76
|
+
Relative dates (`today`, `yesterday`, `tomorrow`, `last_week`, `next_week`) are resolved to ISO date strings at parse time.
|
|
77
|
+
|
|
78
|
+
Multiple `--filter` flags combine with AND logic via `buildCompoundFilter()`.
|
|
79
|
+
|
|
80
|
+
### Markdown ↔ Blocks
|
|
81
|
+
|
|
82
|
+
`markdownToBlocks()` parses: headings (h1-h3), bullet lists, numbered lists, todo items, code blocks (fenced with language), blockquotes, dividers (`---`), and paragraphs with inline formatting (bold, italic, code, links).
|
|
83
|
+
|
|
84
|
+
`blocksToMarkdown()` reverses the process for export.
|
|
85
|
+
|
|
86
|
+
### Multi-Workspace
|
|
87
|
+
|
|
88
|
+
Config format supports named workspace profiles:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"activeWorkspace": "default",
|
|
93
|
+
"workspaces": {
|
|
94
|
+
"default": { "apiKey": "ntn_...", "aliases": { ... } },
|
|
95
|
+
"work": { "apiKey": "ntn_...", "aliases": { ... } }
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Old flat configs (`{ apiKey, aliases }`) are auto-migrated to `{ workspaces: { default: { apiKey, aliases } } }` on first load.
|
|
101
|
+
|
|
102
|
+
## Testing
|
|
103
|
+
|
|
104
|
+
- **`test/unit.test.js`** — Pure function tests (no API calls). Covers all helpers: parsing, formatting, filtering, markdown, CSV.
|
|
105
|
+
- **`test/mock.test.js`** — Command logic with mocked Notion client. Config management, filter building, schema resolution.
|
|
106
|
+
- **`test/integration.test.js`** — Live API tests (requires `NOTION_API_KEY`). Skipped in CI.
|
|
107
|
+
|
|
108
|
+
Run tests: `npm test`
|
|
109
|
+
|
|
110
|
+
## Built On
|
|
111
|
+
|
|
112
|
+
- [`@notionhq/client`](https://github.com/makenotion/notion-sdk-js) v5.x (official Notion SDK)
|
|
113
|
+
- [`commander`](https://github.com/tj/commander.js) for CLI parsing
|
|
114
|
+
- `node:test` + `node:assert` for testing (zero test dependencies)
|
|
115
|
+
|
|
116
|
+
## Contributing
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
git clone https://github.com/JordanCoin/notioncli.git
|
|
120
|
+
cd notioncli
|
|
121
|
+
npm install
|
|
122
|
+
export NOTION_API_KEY=ntn_your_test_key
|
|
123
|
+
npm test
|
|
124
|
+
node bin/notion.js --help
|
|
125
|
+
```
|