@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.
@@ -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
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
  [![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg)](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 decisions, and testing: see **[TECHNICAL.md](./TECHNICAL.md)**.
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
- `blocksToMarkdown()` reverses the process for export.
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
- - **`test/unit.test.js`** Pure function tests (no API calls). Covers all helpers: parsing, formatting, filtering, markdown, CSV.
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