mdview-cli 0.1.0__tar.gz → 1.1.0__tar.gz
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.
- mdview_cli-1.1.0/.github/workflows/release.yml +53 -0
- mdview_cli-1.1.0/.gitignore +6 -0
- mdview_cli-1.1.0/PKG-INFO +170 -0
- mdview_cli-1.1.0/README.md +152 -0
- {mdview_cli-0.1.0 → mdview_cli-1.1.0}/pyproject.toml +3 -3
- mdview_cli-1.1.0/src/mdview_cli/__init__.py +0 -0
- {mdview_cli-0.1.0 → mdview_cli-1.1.0}/src/mdview_cli/api.py +28 -11
- {mdview_cli-0.1.0 → mdview_cli-1.1.0}/src/mdview_cli/cli.py +188 -25
- {mdview_cli-0.1.0 → mdview_cli-1.1.0}/src/mdview_cli/state.py +12 -7
- mdview_cli-1.1.0/src/mdview_cli.egg-info/PKG-INFO +170 -0
- {mdview_cli-0.1.0 → mdview_cli-1.1.0}/src/mdview_cli.egg-info/SOURCES.txt +7 -1
- mdview_cli-1.1.0/src/mdview_cli.egg-info/scm_file_list.json +17 -0
- mdview_cli-1.1.0/src/mdview_cli.egg-info/scm_version.json +8 -0
- mdview_cli-1.1.0/tests/e2e/test_free_tools.py +75 -0
- mdview_cli-1.1.0/tests/test_api.py +61 -0
- mdview_cli-1.1.0/tests/test_cli.py +371 -0
- mdview_cli-0.1.0/PKG-INFO +0 -63
- mdview_cli-0.1.0/README.md +0 -45
- mdview_cli-0.1.0/src/mdview_cli/__init__.py +0 -1
- mdview_cli-0.1.0/src/mdview_cli.egg-info/PKG-INFO +0 -63
- mdview_cli-0.1.0/tests/test_cli.py +0 -185
- {mdview_cli-0.1.0 → mdview_cli-1.1.0}/LICENSE +0 -0
- {mdview_cli-0.1.0 → mdview_cli-1.1.0}/setup.cfg +0 -0
- {mdview_cli-0.1.0 → mdview_cli-1.1.0}/src/mdview_cli/config.py +0 -0
- {mdview_cli-0.1.0 → mdview_cli-1.1.0}/src/mdview_cli.egg-info/dependency_links.txt +0 -0
- {mdview_cli-0.1.0 → mdview_cli-1.1.0}/src/mdview_cli.egg-info/entry_points.txt +0 -0
- {mdview_cli-0.1.0 → mdview_cli-1.1.0}/src/mdview_cli.egg-info/requires.txt +0 -0
- {mdview_cli-0.1.0 → mdview_cli-1.1.0}/src/mdview_cli.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: CLI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
branches:
|
|
8
|
+
- main
|
|
9
|
+
pull_request:
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
strategy:
|
|
15
|
+
matrix:
|
|
16
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v7
|
|
19
|
+
- uses: actions/setup-python@v6
|
|
20
|
+
with:
|
|
21
|
+
python-version: ${{ matrix.python-version }}
|
|
22
|
+
- run: python -m pip install -e '.[test]'
|
|
23
|
+
- run: python -m pytest tests/test_cli.py
|
|
24
|
+
|
|
25
|
+
e2e-free-tools:
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v7
|
|
29
|
+
- uses: actions/setup-python@v6
|
|
30
|
+
with:
|
|
31
|
+
python-version: "3.12"
|
|
32
|
+
- run: python -m pip install -e '.[test]'
|
|
33
|
+
- run: python -m pytest tests/e2e
|
|
34
|
+
|
|
35
|
+
publish:
|
|
36
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
37
|
+
needs: [test, e2e-free-tools]
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
environment: pypi
|
|
40
|
+
permissions:
|
|
41
|
+
id-token: write
|
|
42
|
+
steps:
|
|
43
|
+
- uses: actions/checkout@v7
|
|
44
|
+
with:
|
|
45
|
+
fetch-depth: 0
|
|
46
|
+
- uses: actions/setup-python@v6
|
|
47
|
+
with:
|
|
48
|
+
python-version: "3.12"
|
|
49
|
+
- run: python -m pip install build
|
|
50
|
+
- run: python -m build
|
|
51
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
52
|
+
with:
|
|
53
|
+
packages-dir: dist/
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mdview-cli
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Iterate on Markdown and verify every revision with mdview.io
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://mdview.io
|
|
7
|
+
Project-URL: Repository, https://github.com/gogainda/mdview-cli
|
|
8
|
+
Project-URL: Issues, https://github.com/gogainda/mdview-cli/issues
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: click>=8.1
|
|
13
|
+
Requires-Dist: httpx>=0.27
|
|
14
|
+
Requires-Dist: platformdirs>=4.0
|
|
15
|
+
Provides-Extra: test
|
|
16
|
+
Requires-Dist: pytest>=8.0; extra == "test"
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# mdv — preview Markdown files from your terminal
|
|
20
|
+
|
|
21
|
+
`mdv` renders a Markdown file the way it should look — headings, tables, code,
|
|
22
|
+
Mermaid diagrams — and opens it in your browser. One command, no account, no
|
|
23
|
+
configuration.
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
uv tool install mdview-cli # or: pipx install mdview-cli, pip install mdview-cli
|
|
27
|
+
mdv notes.md
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Homebrew users:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
brew install gogainda/tap/mdview-cli
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
That's the whole workflow: `mdv FILE.md` publishes the file to
|
|
37
|
+
[mdview.io](https://mdview.io), opens the rendered page, and prints a link you
|
|
38
|
+
can send to anyone. Anonymous previews last 30 days and take files up to 2 MB.
|
|
39
|
+
|
|
40
|
+
## Two ways to preview
|
|
41
|
+
|
|
42
|
+
**Shareable preview (default).** `mdv FILE.md` is shorthand for `mdv preview
|
|
43
|
+
FILE.md`. The title comes from the first `#` heading, or pass your own:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
mdv notes.md
|
|
47
|
+
mdv preview notes.md --title "Design notes"
|
|
48
|
+
mdv preview notes.md --json # print the share URLs as JSON, don't open a browser
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Local-only preview.** `mdv open` uploads nothing: it packs the file into the
|
|
52
|
+
URL itself and rendering happens entirely in your browser. Use it for drafts
|
|
53
|
+
that shouldn't leave your machine.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
mdv open notes.md
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Iterating on one document
|
|
60
|
+
|
|
61
|
+
Previews are throwaway: every run mints a new link. When you keep working on
|
|
62
|
+
the same file — a spec, an architecture doc, a report — you want the opposite:
|
|
63
|
+
one stable URL whose content follows your edits, and a check that every
|
|
64
|
+
revision still renders cleanly.
|
|
65
|
+
|
|
66
|
+
Set up a free mdview.io CLI token once, then it's one command per iteration:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
mdv keys set # once (or set MDVIEW_TOKEN in CI)
|
|
70
|
+
mdv sync spec.md # publish this revision, verify it, auto-repair broken diagrams
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
While you iterate, the document lives at its **private** `/p/` page — only
|
|
74
|
+
you, signed in, can see it, and the URL stays the same forever. Every sync
|
|
75
|
+
shows the fixed, renderable version there. Broken Mermaid diagrams are
|
|
76
|
+
repaired automatically and the fix is written back into your file (the
|
|
77
|
+
original is kept as a timestamped backup); only documents that can't be
|
|
78
|
+
repaired exit `1`.
|
|
79
|
+
|
|
80
|
+
When — and only when — you decide to publish, make it public; and grab a PDF
|
|
81
|
+
at any point:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
mdv share spec.md # mint the public /s/ link (from then on it follows your syncs)
|
|
85
|
+
mdv share spec.md --slug my-doc # …or with a custom /s/my-doc slug
|
|
86
|
+
mdv export spec.md # render the current revision to spec.pdf
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Or do both steps at once — sync, auto-repair, and share in one call:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
mdv publish spec.md --slug my-doc # sync + repair + share, atomically
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Useful around the loop:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
mdv sync spec.md --no-fix # fast sync: skip auto-repair, just report failures
|
|
99
|
+
mdv export spec.md --no-sync # PDF of the last synced revision; local edits stay private
|
|
100
|
+
mdv list # all saved documents with their URLs
|
|
101
|
+
mdv status spec.md # document ID, public state, last sync, local edits pending?
|
|
102
|
+
mdv unlink spec.md # forget the file↔document link; the document stays online
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Nothing is public until you run `mdv share`. After that, the public page
|
|
106
|
+
serves the last synced revision — mid-edit local changes still stay private
|
|
107
|
+
until you sync. `mdv fix FILE --local` repairs a file in place without
|
|
108
|
+
creating a saved document (free accounts share the daily Quick Fix limit;
|
|
109
|
+
Pro is unlimited).
|
|
110
|
+
|
|
111
|
+
### Example session
|
|
112
|
+
|
|
113
|
+
A real session, working on a doc whose Mermaid diagrams start out broken:
|
|
114
|
+
|
|
115
|
+
```console
|
|
116
|
+
$ mdv sync spec.md # iterate — the broken flowchart is auto-repaired (~30s)
|
|
117
|
+
Document: 8be0be9198400443
|
|
118
|
+
Private: https://mdview.io/p/8be0be9198400443
|
|
119
|
+
Renderable: yes (1 diagrams, 0 tables)
|
|
120
|
+
|
|
121
|
+
$ vim spec.md # …add two sections, each with a (broken) diagram…
|
|
122
|
+
$ mdv sync spec.md # same doc, all three diagrams repaired and verified
|
|
123
|
+
Document: 8be0be9198400443
|
|
124
|
+
Private: https://mdview.io/p/8be0be9198400443
|
|
125
|
+
Renderable: yes (3 diagrams, 0 tables)
|
|
126
|
+
|
|
127
|
+
$ mdv share spec.md # happy with it — make it public
|
|
128
|
+
https://mdview.io/s/9a2b8fb1
|
|
129
|
+
|
|
130
|
+
$ mdv export spec.md # …and hand over a PDF
|
|
131
|
+
PDF: spec.pdf
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Two commands did all the work: `mdv sync` after every editing round, and
|
|
135
|
+
`mdv share` once at the end. The fixes were written back into `spec.md`
|
|
136
|
+
(originals in timestamped backups, so you can review what the repair
|
|
137
|
+
changed — worth a glance before sharing, since a repair is guaranteed to
|
|
138
|
+
render but not to read your mind), the private URL never changed, and the
|
|
139
|
+
public link didn't exist until it was asked for.
|
|
140
|
+
|
|
141
|
+
**When this flow fits:** a document that lives longer than one paste — specs,
|
|
142
|
+
architecture docs, reports, runbooks, agent-written docs you refine over
|
|
143
|
+
hours or days. Use it when reviewers follow one link that must always show
|
|
144
|
+
the latest good revision, when a PDF has to be producible at any moment, or
|
|
145
|
+
in CI as a docs gate (`mdv sync --no-fix` exits `1` on broken diagrams
|
|
146
|
+
without editing anything). For a one-off snapshot, `mdv preview` is enough;
|
|
147
|
+
for reading a local file without uploading it, use `mdv open`.
|
|
148
|
+
|
|
149
|
+
## Reference
|
|
150
|
+
|
|
151
|
+
| Command | Token | What it does |
|
|
152
|
+
|---|---|---|
|
|
153
|
+
| `mdv FILE.md` / `mdv preview` | no | Publish anonymously, open the rendered page (30-day link) |
|
|
154
|
+
| `mdv open` | no | Render locally in the browser; nothing is uploaded |
|
|
155
|
+
| `mdv sync` | yes | Update a saved document at its private /p/ URL, verify + auto-repair |
|
|
156
|
+
| `mdv share` | yes | Make a synced document public at its /s/ URL, optionally with `--slug` |
|
|
157
|
+
| `mdv publish` | yes | Sync + auto-repair + share in one call |
|
|
158
|
+
| `mdv verify` | yes | Re-check rendering of a synced document |
|
|
159
|
+
| `mdv fix` | yes | Repair broken Mermaid diagrams, with a local backup |
|
|
160
|
+
| `mdv export` | yes | Export a synced document to PDF |
|
|
161
|
+
| `mdv list` | yes | List saved documents |
|
|
162
|
+
| `mdv status` | yes | Show a synced document's ID, public state, slug, and whether local edits are unsynced |
|
|
163
|
+
| `mdv unlink` | no | Remove the local file↔document association |
|
|
164
|
+
| `mdv keys set/list/path/unset` | — | Manage the stored CLI token |
|
|
165
|
+
|
|
166
|
+
Exit codes: `0` success, `1` document doesn't render cleanly, `2` usage error,
|
|
167
|
+
`3` mdview.io error.
|
|
168
|
+
|
|
169
|
+
Environment: `MDVIEW_TOKEN` supplies the token without storing it (ideal for
|
|
170
|
+
CI); `MDVIEW_BASE_URL` points the CLI at another server.
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# mdv — preview Markdown files from your terminal
|
|
2
|
+
|
|
3
|
+
`mdv` renders a Markdown file the way it should look — headings, tables, code,
|
|
4
|
+
Mermaid diagrams — and opens it in your browser. One command, no account, no
|
|
5
|
+
configuration.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
uv tool install mdview-cli # or: pipx install mdview-cli, pip install mdview-cli
|
|
9
|
+
mdv notes.md
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Homebrew users:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
brew install gogainda/tap/mdview-cli
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
That's the whole workflow: `mdv FILE.md` publishes the file to
|
|
19
|
+
[mdview.io](https://mdview.io), opens the rendered page, and prints a link you
|
|
20
|
+
can send to anyone. Anonymous previews last 30 days and take files up to 2 MB.
|
|
21
|
+
|
|
22
|
+
## Two ways to preview
|
|
23
|
+
|
|
24
|
+
**Shareable preview (default).** `mdv FILE.md` is shorthand for `mdv preview
|
|
25
|
+
FILE.md`. The title comes from the first `#` heading, or pass your own:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
mdv notes.md
|
|
29
|
+
mdv preview notes.md --title "Design notes"
|
|
30
|
+
mdv preview notes.md --json # print the share URLs as JSON, don't open a browser
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Local-only preview.** `mdv open` uploads nothing: it packs the file into the
|
|
34
|
+
URL itself and rendering happens entirely in your browser. Use it for drafts
|
|
35
|
+
that shouldn't leave your machine.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
mdv open notes.md
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Iterating on one document
|
|
42
|
+
|
|
43
|
+
Previews are throwaway: every run mints a new link. When you keep working on
|
|
44
|
+
the same file — a spec, an architecture doc, a report — you want the opposite:
|
|
45
|
+
one stable URL whose content follows your edits, and a check that every
|
|
46
|
+
revision still renders cleanly.
|
|
47
|
+
|
|
48
|
+
Set up a free mdview.io CLI token once, then it's one command per iteration:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
mdv keys set # once (or set MDVIEW_TOKEN in CI)
|
|
52
|
+
mdv sync spec.md # publish this revision, verify it, auto-repair broken diagrams
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
While you iterate, the document lives at its **private** `/p/` page — only
|
|
56
|
+
you, signed in, can see it, and the URL stays the same forever. Every sync
|
|
57
|
+
shows the fixed, renderable version there. Broken Mermaid diagrams are
|
|
58
|
+
repaired automatically and the fix is written back into your file (the
|
|
59
|
+
original is kept as a timestamped backup); only documents that can't be
|
|
60
|
+
repaired exit `1`.
|
|
61
|
+
|
|
62
|
+
When — and only when — you decide to publish, make it public; and grab a PDF
|
|
63
|
+
at any point:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
mdv share spec.md # mint the public /s/ link (from then on it follows your syncs)
|
|
67
|
+
mdv share spec.md --slug my-doc # …or with a custom /s/my-doc slug
|
|
68
|
+
mdv export spec.md # render the current revision to spec.pdf
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Or do both steps at once — sync, auto-repair, and share in one call:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
mdv publish spec.md --slug my-doc # sync + repair + share, atomically
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Useful around the loop:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
mdv sync spec.md --no-fix # fast sync: skip auto-repair, just report failures
|
|
81
|
+
mdv export spec.md --no-sync # PDF of the last synced revision; local edits stay private
|
|
82
|
+
mdv list # all saved documents with their URLs
|
|
83
|
+
mdv status spec.md # document ID, public state, last sync, local edits pending?
|
|
84
|
+
mdv unlink spec.md # forget the file↔document link; the document stays online
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Nothing is public until you run `mdv share`. After that, the public page
|
|
88
|
+
serves the last synced revision — mid-edit local changes still stay private
|
|
89
|
+
until you sync. `mdv fix FILE --local` repairs a file in place without
|
|
90
|
+
creating a saved document (free accounts share the daily Quick Fix limit;
|
|
91
|
+
Pro is unlimited).
|
|
92
|
+
|
|
93
|
+
### Example session
|
|
94
|
+
|
|
95
|
+
A real session, working on a doc whose Mermaid diagrams start out broken:
|
|
96
|
+
|
|
97
|
+
```console
|
|
98
|
+
$ mdv sync spec.md # iterate — the broken flowchart is auto-repaired (~30s)
|
|
99
|
+
Document: 8be0be9198400443
|
|
100
|
+
Private: https://mdview.io/p/8be0be9198400443
|
|
101
|
+
Renderable: yes (1 diagrams, 0 tables)
|
|
102
|
+
|
|
103
|
+
$ vim spec.md # …add two sections, each with a (broken) diagram…
|
|
104
|
+
$ mdv sync spec.md # same doc, all three diagrams repaired and verified
|
|
105
|
+
Document: 8be0be9198400443
|
|
106
|
+
Private: https://mdview.io/p/8be0be9198400443
|
|
107
|
+
Renderable: yes (3 diagrams, 0 tables)
|
|
108
|
+
|
|
109
|
+
$ mdv share spec.md # happy with it — make it public
|
|
110
|
+
https://mdview.io/s/9a2b8fb1
|
|
111
|
+
|
|
112
|
+
$ mdv export spec.md # …and hand over a PDF
|
|
113
|
+
PDF: spec.pdf
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Two commands did all the work: `mdv sync` after every editing round, and
|
|
117
|
+
`mdv share` once at the end. The fixes were written back into `spec.md`
|
|
118
|
+
(originals in timestamped backups, so you can review what the repair
|
|
119
|
+
changed — worth a glance before sharing, since a repair is guaranteed to
|
|
120
|
+
render but not to read your mind), the private URL never changed, and the
|
|
121
|
+
public link didn't exist until it was asked for.
|
|
122
|
+
|
|
123
|
+
**When this flow fits:** a document that lives longer than one paste — specs,
|
|
124
|
+
architecture docs, reports, runbooks, agent-written docs you refine over
|
|
125
|
+
hours or days. Use it when reviewers follow one link that must always show
|
|
126
|
+
the latest good revision, when a PDF has to be producible at any moment, or
|
|
127
|
+
in CI as a docs gate (`mdv sync --no-fix` exits `1` on broken diagrams
|
|
128
|
+
without editing anything). For a one-off snapshot, `mdv preview` is enough;
|
|
129
|
+
for reading a local file without uploading it, use `mdv open`.
|
|
130
|
+
|
|
131
|
+
## Reference
|
|
132
|
+
|
|
133
|
+
| Command | Token | What it does |
|
|
134
|
+
|---|---|---|
|
|
135
|
+
| `mdv FILE.md` / `mdv preview` | no | Publish anonymously, open the rendered page (30-day link) |
|
|
136
|
+
| `mdv open` | no | Render locally in the browser; nothing is uploaded |
|
|
137
|
+
| `mdv sync` | yes | Update a saved document at its private /p/ URL, verify + auto-repair |
|
|
138
|
+
| `mdv share` | yes | Make a synced document public at its /s/ URL, optionally with `--slug` |
|
|
139
|
+
| `mdv publish` | yes | Sync + auto-repair + share in one call |
|
|
140
|
+
| `mdv verify` | yes | Re-check rendering of a synced document |
|
|
141
|
+
| `mdv fix` | yes | Repair broken Mermaid diagrams, with a local backup |
|
|
142
|
+
| `mdv export` | yes | Export a synced document to PDF |
|
|
143
|
+
| `mdv list` | yes | List saved documents |
|
|
144
|
+
| `mdv status` | yes | Show a synced document's ID, public state, slug, and whether local edits are unsynced |
|
|
145
|
+
| `mdv unlink` | no | Remove the local file↔document association |
|
|
146
|
+
| `mdv keys set/list/path/unset` | — | Manage the stored CLI token |
|
|
147
|
+
|
|
148
|
+
Exit codes: `0` success, `1` document doesn't render cleanly, `2` usage error,
|
|
149
|
+
`3` mdview.io error.
|
|
150
|
+
|
|
151
|
+
Environment: `MDVIEW_TOKEN` supplies the token without storing it (ideal for
|
|
152
|
+
CI); `MDVIEW_BASE_URL` points the CLI at another server.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["setuptools>=69"]
|
|
2
|
+
requires = ["setuptools>=69", "setuptools-scm>=8"]
|
|
3
3
|
build-backend = "setuptools.build_meta"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
@@ -29,8 +29,8 @@ mdv = "mdview_cli.cli:cli"
|
|
|
29
29
|
[tool.setuptools.packages.find]
|
|
30
30
|
where = ["src"]
|
|
31
31
|
|
|
32
|
-
[tool.
|
|
33
|
-
|
|
32
|
+
[tool.setuptools_scm]
|
|
33
|
+
fallback_version = "0.0.0"
|
|
34
34
|
|
|
35
35
|
[tool.pytest.ini_options]
|
|
36
36
|
testpaths = ["tests"]
|
|
File without changes
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import time
|
|
2
|
+
|
|
1
3
|
import httpx
|
|
2
4
|
|
|
5
|
+
BUSY_RETRY_ATTEMPTS = 4
|
|
6
|
+
BUSY_RETRY_DELAY = 1.0
|
|
7
|
+
|
|
3
8
|
|
|
4
9
|
class ApiError(RuntimeError):
|
|
5
10
|
def __init__(self, message: str, status_code: int | None = None):
|
|
@@ -16,18 +21,24 @@ class MdviewApi:
|
|
|
16
21
|
)
|
|
17
22
|
|
|
18
23
|
def request(self, method: str, path: str, **kwargs):
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
except httpx.HTTPError as error:
|
|
22
|
-
raise ApiError(f"Could not reach mdview.io: {error}") from error
|
|
23
|
-
if response.is_error:
|
|
24
|
+
delay = BUSY_RETRY_DELAY
|
|
25
|
+
for attempt in range(BUSY_RETRY_ATTEMPTS):
|
|
24
26
|
try:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
response = self.client.request(method, path, **kwargs)
|
|
28
|
+
except httpx.HTTPError as error:
|
|
29
|
+
raise ApiError(f"Could not reach mdview.io: {error}") from error
|
|
30
|
+
if response.is_error:
|
|
31
|
+
try:
|
|
32
|
+
body = response.json()
|
|
33
|
+
message = body.get("message") or body.get("error") or response.reason_phrase
|
|
34
|
+
except ValueError:
|
|
35
|
+
message = response.reason_phrase
|
|
36
|
+
if "busy" in str(message).lower() and attempt < BUSY_RETRY_ATTEMPTS - 1:
|
|
37
|
+
time.sleep(delay)
|
|
38
|
+
delay *= 2
|
|
39
|
+
continue
|
|
40
|
+
raise ApiError(str(message), response.status_code)
|
|
41
|
+
return response
|
|
31
42
|
|
|
32
43
|
def create(self, title, content):
|
|
33
44
|
return self.request("POST", "/api/documents", json={"title": title, "content": content}).json()
|
|
@@ -44,6 +55,9 @@ class MdviewApi:
|
|
|
44
55
|
def share(self, document_id):
|
|
45
56
|
return self.request("POST", f"/api/documents/{document_id}/share", json={}).json()
|
|
46
57
|
|
|
58
|
+
def set_slug(self, document_id, slug):
|
|
59
|
+
return self.request("PATCH", f"/api/documents/{document_id}/share/slug", json={"slug": slug}).json()
|
|
60
|
+
|
|
47
61
|
def verify(self, document_id, status=False):
|
|
48
62
|
suffix = "/status" if status else ""
|
|
49
63
|
return self.request("GET", f"/api/documents/{document_id}/verify{suffix}").json()
|
|
@@ -51,6 +65,9 @@ class MdviewApi:
|
|
|
51
65
|
def fix(self, document_id):
|
|
52
66
|
return self.request("POST", f"/api/documents/{document_id}/fix/diagrams", json={}).json()
|
|
53
67
|
|
|
68
|
+
def fix_markdown(self, content):
|
|
69
|
+
return self.request("POST", "/api/documents/fix/diagrams", json={"content": content}).json()
|
|
70
|
+
|
|
54
71
|
def export_pdf(self, document_id):
|
|
55
72
|
return self.request("GET", f"/api/documents/{document_id}/export/pdf").content
|
|
56
73
|
|