@jordancoin/notioncli 1.3.0 → 1.3.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/.github/workflows/publish.yml +74 -0
- package/README.md +12 -2
- package/TECHNICAL.md +63 -3
- package/bin/notion.js +18 -1676
- package/commands/blocks.js +142 -0
- package/commands/comments.js +59 -0
- package/commands/config.js +328 -0
- package/commands/crud.js +196 -0
- package/commands/database.js +241 -0
- package/commands/import-export.js +162 -0
- package/commands/pages.js +203 -0
- package/commands/query.js +73 -0
- package/commands/search.js +45 -0
- package/commands/upload.js +84 -0
- package/commands/users.js +73 -0
- package/lib/context.js +359 -0
- package/lib/filters.js +55 -11
- package/lib/format.js +35 -2
- package/lib/helpers.js +4 -0
- package/lib/markdown.js +179 -38
- package/lib/paginate.js +74 -0
- package/lib/retry.js +76 -0
- package/package.json +1 -1
- package/skill/SKILL.md +7 -0
- package/skill/marketplace.json +2 -2
- package/test/unit.test.js +270 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
bump:
|
|
7
|
+
description: 'Version bump type'
|
|
8
|
+
required: true
|
|
9
|
+
type: choice
|
|
10
|
+
options:
|
|
11
|
+
- patch
|
|
12
|
+
- minor
|
|
13
|
+
- major
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: write
|
|
17
|
+
id-token: write
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
publish:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
with:
|
|
25
|
+
fetch-depth: 0
|
|
26
|
+
|
|
27
|
+
- uses: actions/setup-node@v4
|
|
28
|
+
with:
|
|
29
|
+
node-version: 22
|
|
30
|
+
registry-url: https://registry.npmjs.org
|
|
31
|
+
|
|
32
|
+
- run: npm ci
|
|
33
|
+
|
|
34
|
+
- name: Run tests
|
|
35
|
+
run: npm test
|
|
36
|
+
|
|
37
|
+
- name: Configure git
|
|
38
|
+
run: |
|
|
39
|
+
git config user.name "github-actions[bot]"
|
|
40
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
41
|
+
|
|
42
|
+
- name: Bump version
|
|
43
|
+
id: bump
|
|
44
|
+
run: |
|
|
45
|
+
# Bump package.json (no git tag yet)
|
|
46
|
+
NEW_VERSION=$(npm version ${{ inputs.bump }} --no-git-tag-version)
|
|
47
|
+
echo "version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
|
|
48
|
+
echo "version_bare=${NEW_VERSION#v}" >> "$GITHUB_OUTPUT"
|
|
49
|
+
|
|
50
|
+
- name: Update version in bin/notion.js
|
|
51
|
+
run: |
|
|
52
|
+
sed -i "s/\.version('[^']*')/\.version('${{ steps.bump.outputs.version_bare }}')/" bin/notion.js
|
|
53
|
+
|
|
54
|
+
- name: Update version in skill/marketplace.json
|
|
55
|
+
run: |
|
|
56
|
+
sed -i 's/"version": "[^"]*"/"version": "${{ steps.bump.outputs.version_bare }}"/' skill/marketplace.json
|
|
57
|
+
|
|
58
|
+
- name: Commit, tag, push
|
|
59
|
+
run: |
|
|
60
|
+
git add -A
|
|
61
|
+
git commit -m "chore: bump version to ${{ steps.bump.outputs.version_bare }}"
|
|
62
|
+
git tag ${{ steps.bump.outputs.version }}
|
|
63
|
+
git push origin main --tags
|
|
64
|
+
|
|
65
|
+
- name: Create GitHub Release
|
|
66
|
+
env:
|
|
67
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
68
|
+
run: |
|
|
69
|
+
gh release create ${{ steps.bump.outputs.version }} \
|
|
70
|
+
--title "${{ steps.bump.outputs.version }}" \
|
|
71
|
+
--generate-notes
|
|
72
|
+
|
|
73
|
+
- name: Publish to npm (OIDC trusted publisher — no token needed)
|
|
74
|
+
run: npm publish --access public --provenance
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
[](https://nodejs.org/)
|
|
7
7
|
|
|
8
|
-
A CLI for the Notion API. Aliases instead of UUIDs, property names as flags, full CRUD. Built for humans and AI agents.
|
|
8
|
+
A CLI for the Notion API. Aliases instead of UUIDs, property names as flags, full CRUD, automatic pagination, rate limit retry. Built for humans and AI agents.
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
11
|
npm install -g @jordancoin/notioncli
|
|
@@ -110,6 +110,10 @@ notion query tasks --filter Status=Active --filter Priority=High
|
|
|
110
110
|
# Relative dates
|
|
111
111
|
notion query tasks --filter "Due=today"
|
|
112
112
|
notion query tasks --filter "Created>=last_week"
|
|
113
|
+
|
|
114
|
+
# Values containing operators (parsed correctly)
|
|
115
|
+
notion query tasks --filter "Description=score>=90"
|
|
116
|
+
notion query tasks --filter 'Notes="contains quotes"'
|
|
113
117
|
```
|
|
114
118
|
|
|
115
119
|
### Dynamic property flags
|
|
@@ -216,9 +220,15 @@ notion workspace list # see workspaces
|
|
|
216
220
|
|
|
217
221
|
---
|
|
218
222
|
|
|
223
|
+
## Reliability
|
|
224
|
+
|
|
225
|
+
- **Automatic pagination** — All list endpoints fetch every result by default. Use `--limit` to cap.
|
|
226
|
+
- **Rate limit retry** — 429 responses trigger exponential backoff with jitter (up to 5 attempts). Transparent — no flags needed.
|
|
227
|
+
- **Input validation** — Numbers, dates, URLs, and emails are validated before hitting the API. Clear error messages instead of cryptic 400s.
|
|
228
|
+
|
|
219
229
|
## Technical Details
|
|
220
230
|
|
|
221
|
-
For API internals, the 2025 dual-ID system, architecture
|
|
231
|
+
For API internals, the 2025 dual-ID system, modular architecture, and testing (213 tests): see **[TECHNICAL.md](./TECHNICAL.md)**.
|
|
222
232
|
|
|
223
233
|
---
|
|
224
234
|
|
package/TECHNICAL.md
CHANGED
|
@@ -43,6 +43,35 @@ The `dataSources` namespace provides: `retrieve`, `query`, `create`, `update`, `
|
|
|
43
43
|
|
|
44
44
|
## Architecture
|
|
45
45
|
|
|
46
|
+
### Modular Command Structure (v1.3.1)
|
|
47
|
+
|
|
48
|
+
`bin/notion.js` is a thin orchestrator (~28 lines). All logic lives in modules:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
bin/notion.js — CLI entry point, registers commands
|
|
52
|
+
lib/context.js — Shared context factory (config, auth, Notion client, schema helpers)
|
|
53
|
+
lib/helpers.js — Re-exports all lib modules
|
|
54
|
+
lib/format.js — Output formatting (table, CSV, YAML, JSON), property building
|
|
55
|
+
lib/filters.js — Filter parsing, operator detection, compound filters
|
|
56
|
+
lib/markdown.js — Markdown ↔ Notion blocks, CSV parsing, inline formatting
|
|
57
|
+
lib/config.js — Config load/save, workspace resolution
|
|
58
|
+
lib/paginate.js — Cursor-based pagination
|
|
59
|
+
lib/retry.js — Exponential backoff with jitter for rate limits
|
|
60
|
+
commands/config.js — init, alias (add/remove/list/rename), workspace (add/list/use/remove)
|
|
61
|
+
commands/search.js — search
|
|
62
|
+
commands/query.js — query with filters, sorting, pagination
|
|
63
|
+
commands/crud.js — add, update, delete, get
|
|
64
|
+
commands/blocks.js — blocks, block-edit, block-delete, append
|
|
65
|
+
commands/database.js — dbs, db-create, db-update, templates
|
|
66
|
+
commands/users.js — users, user, me
|
|
67
|
+
commands/comments.js — comments, comment
|
|
68
|
+
commands/pages.js — relations, move, props
|
|
69
|
+
commands/import-export.js — import, export
|
|
70
|
+
commands/upload.js — file upload
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Each command module exports `register(program, ctx)` where `ctx` is the shared context from `createContext(program)`. The context provides config helpers, the lazy Notion client, schema resolution, and all formatting utilities.
|
|
74
|
+
|
|
46
75
|
### Alias Resolution
|
|
47
76
|
|
|
48
77
|
Every command that targets a database goes through `resolveDb(alias_or_id)`:
|
|
@@ -77,11 +106,40 @@ Relative dates (`today`, `yesterday`, `tomorrow`, `last_week`, `next_week`) are
|
|
|
77
106
|
|
|
78
107
|
Multiple `--filter` flags combine with AND logic via `buildCompoundFilter()`.
|
|
79
108
|
|
|
109
|
+
### Pagination (v1.3.1)
|
|
110
|
+
|
|
111
|
+
`paginate()` in `lib/paginate.js` is a generic cursor-based pagination helper. It wraps any Notion API call that returns `{ results, has_more, next_cursor }` and accumulates all pages:
|
|
112
|
+
|
|
113
|
+
- Default behavior fetches all results (no limit)
|
|
114
|
+
- `--limit N` caps results and emits a stderr warning if truncated
|
|
115
|
+
- Used by: search, query, blocks, dbs, users, comments
|
|
116
|
+
|
|
117
|
+
### Rate Limit Retry (v1.3.1)
|
|
118
|
+
|
|
119
|
+
`withRetry()` in `lib/retry.js` wraps API calls with exponential backoff + jitter on 429 responses. The Notion client is wrapped via `wrapNotionClient()` which uses a JS Proxy to transparently intercept all method calls — no code changes needed per-endpoint.
|
|
120
|
+
|
|
121
|
+
Default: 5 attempts, 1s base delay, 2x multiplier, ±25% jitter.
|
|
122
|
+
|
|
123
|
+
### Input Validation (v1.3.1)
|
|
124
|
+
|
|
125
|
+
`buildPropValue()` in `lib/format.js` validates before hitting the API:
|
|
126
|
+
|
|
127
|
+
- **Numbers**: rejects NaN values
|
|
128
|
+
- **Dates**: validates against ISO 8601 (YYYY-MM-DD or full datetime) via regex + Date.parse
|
|
129
|
+
- **URLs**: requires `http://` or `https://` prefix
|
|
130
|
+
- **Emails**: requires `@` character
|
|
131
|
+
|
|
132
|
+
Returns `{ error: "..." }` objects; the caller prints a clear message and exits.
|
|
133
|
+
|
|
80
134
|
### Markdown ↔ Blocks
|
|
81
135
|
|
|
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).
|
|
136
|
+
`markdownToBlocks()` parses: headings (h1-h3), bullet lists (with nested indentation via stack-based tracking), numbered lists, todo items, code blocks (fenced with language), blockquotes, dividers (`---`), and paragraphs with inline formatting (bold, italic, code, links).
|
|
137
|
+
|
|
138
|
+
`blocksToMarkdown()` reverses the process, preserving rich text annotations (bold → `**`, italic → `*`, code → backticks, strikethrough → `~~`, links → `[text](url)`) via `richTextToMarkdown()`.
|
|
83
139
|
|
|
84
|
-
|
|
140
|
+
### CSV Parsing (v1.3.1)
|
|
141
|
+
|
|
142
|
+
`parseCsv()` uses character-by-character scanning to correctly handle quoted fields containing newlines, commas, and escaped quotes (`""`). Previously split on `\n` which broke multiline fields.
|
|
85
143
|
|
|
86
144
|
### Multi-Workspace
|
|
87
145
|
|
|
@@ -101,7 +159,9 @@ Old flat configs (`{ apiKey, aliases }`) are auto-migrated to `{ workspaces: { d
|
|
|
101
159
|
|
|
102
160
|
## Testing
|
|
103
161
|
|
|
104
|
-
|
|
162
|
+
213 tests across 27 suites, zero dependencies (`node:test` + `node:assert`):
|
|
163
|
+
|
|
164
|
+
- **`test/unit.test.js`** — Pure function tests (no API calls). Covers: property formatting (38 types), filter building (26 operators), markdown parsing (10 block types + nested bullets), CSV parsing (multiline fields), inline formatting, pagination, retry logic, input validation, dynamic prop extraction.
|
|
105
165
|
- **`test/mock.test.js`** — Command logic with mocked Notion client. Config management, filter building, schema resolution.
|
|
106
166
|
- **`test/integration.test.js`** — Live API tests (requires `NOTION_API_KEY`). Skipped in CI.
|
|
107
167
|
|