@msout/microsoft-onenote-exporter 0.1.3 → 0.1.4

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/CHANGELOG.md CHANGED
@@ -6,7 +6,47 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
- ## [0.1.3] - 2026-10-02
9
+ ## [0.1.4] - 2026-10-02
10
+
11
+ A **patch**. Three of the five subcommands could not run through
12
+ `start-container.sh` at all, and only `export` had ever been tried.
13
+
14
+ ### Fixed
15
+
16
+ - **`list`, `check` and `logout` were rejected when given no flags**, by a
17
+ `$# -eq 0` guard written for `export` and applied to all five subcommands. Those
18
+ three steps need no arguments; the extra guard is gone and the export-specific
19
+ one is now the only one. Closes #3.
20
+
21
+ - **`logout` cannot be done in a container, and now does not try.** Mounting the
22
+ session read-write and letting the container delete it cannot work: Docker
23
+ mounts a single file at `/data/auth/session.json`, and a container cannot remove
24
+ a mount point, so unlinking it failed with `EACCES` whether the mount was
25
+ read-only or not. Deleting a session is a host-side operation, so the wrapper
26
+ removes the file and its `-meta.json` itself, before an image is even required.
27
+ The session stays mounted read-only for every other step, so a bug in the
28
+ container still cannot destroy it.
29
+
30
+ - **`--auth-file` is no longer silently ignored.** The wrapper picks the session
31
+ itself and passes its own `--auth-file` to the container, so a caller's
32
+ `--auth-file ./my.json` was neither honoured nor rejected — the wrong session
33
+ was used and the run succeeded against it. It is now the highest-precedence
34
+ source, verified with a decoy `output/auth.json` left in place.
35
+
36
+ - **Failure messages name the subcommand.** A failed `logout` reported "the export
37
+ failed and produced nothing usable" and pointed at notes that were never the
38
+ point of the command.
39
+
40
+ Tests: 132 → 137. Five of them fail against 0.1.3, and two assert source *position*
41
+ rather than text, because assertions in this file had already passed against
42
+ broken versions twice: one checked only that a guard existed rather than that it
43
+ was scoped to `export`, and another matched a path that a comment matched first.
44
+
45
+ Verified against a real account, all four through the wrapper: `list` exits 0 with
46
+ 12 notebooks, `check` exits 0 reporting Authenticated, `logout` removes the session
47
+ and its metadata with no image needed, and `export` still produces 19 notes.
48
+
49
+ ## [0.1.3] - 2026-10-02 - 2026-10-02
10
50
 
11
51
  A **patch**, and the first release driven by the automation added in the previous
12
52
  one rather than by remembering to check.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@msout/microsoft-onenote-exporter",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Log in, list and export Microsoft OneNote notebooks as Obsidian Markdown - one CLI over @msout/microsoft-webauth, @msout/microsoft-onenote-list-notebooks and @msout/microsoft-onenote-export-notebook.",
5
5
  "main": "src/index.js",
6
6
  "exports": {
@@ -33,23 +33,46 @@ OUTPUT_DIR="${OUTPUT_DIR:-./output}"
33
33
  # simply follows it and no copy is needed.
34
34
  # Which session to use, in order of preference:
35
35
  #
36
- # 1. $AUTH_FILE, if the caller set it
37
- # 2. ./output/auth.json, the convention the README documents - the session sits
36
+ # 1. --auth-file <path>, if the caller passed it on the command line
37
+ # 2. $AUTH_FILE, if the caller set it in the environment
38
+ # 3. ./output/auth.json, the convention the README documents - the session sits
38
39
  # beside the notes in the one mounted volume, so there is nothing else to
39
40
  # mount and no copy step on every run
40
- # 3. ~/.microsoft-webauth/auth-file.json, where `login` writes it, so the
41
+ # 4. ~/.microsoft-webauth/auth-file.json, where `login` writes it, so the
41
42
  # "log in on the host, then run this" sequence works with no preparation
42
43
  #
43
- # The default is NOT just (3): a check for (2) has to come first, because with the
44
- # default set to (3) the script looks for a file named `auth-file.json` in the
44
+ # (1) exists because the flag was silently ignored. This script picks the session
45
+ # itself and passes its own --auth-file to the container, so an
46
+ # `--auth-file ./my.json` from the caller was neither honoured nor rejected - the
47
+ # wrong session was used and the run succeeded against it. Found by passing the
48
+ # flag, watching a *different* file get deleted, and reading the code to see why.
49
+ #
50
+ # The default is NOT just (4): a check for (3) has to come first, because with the
51
+ # default set to (4) the script looks for a file named `auth-file.json` in the
45
52
  # output directory and silently ignores the `auth.json` a user following the
46
53
  # README actually placed there.
47
- if [ -z "${AUTH_FILE:-}" ]; then
48
- if [ -f "${OUTPUT_DIR}/auth.json" ]; then
49
- AUTH_FILE="${OUTPUT_DIR}/auth.json"
50
- else
51
- AUTH_FILE="$HOME/.microsoft-webauth/auth-file.json"
54
+ AUTH_FILE_FROM_ARGS=""
55
+ prev=""
56
+ for arg in "$@"; do
57
+ if [ "$prev" = "--auth-file" ]; then
58
+ AUTH_FILE_FROM_ARGS="$arg"
52
59
  fi
60
+ case "$arg" in
61
+ --auth-file=*)
62
+ AUTH_FILE_FROM_ARGS="${arg#--auth-file=}"
63
+ ;;
64
+ esac
65
+ prev="$arg"
66
+ done
67
+
68
+ if [ -n "$AUTH_FILE_FROM_ARGS" ]; then
69
+ AUTH_FILE="$AUTH_FILE_FROM_ARGS"
70
+ elif [ -n "${AUTH_FILE:-}" ]; then
71
+ AUTH_FILE="$AUTH_FILE"
72
+ elif [ -f "${OUTPUT_DIR}/auth.json" ]; then
73
+ AUTH_FILE="${OUTPUT_DIR}/auth.json"
74
+ else
75
+ AUTH_FILE="$HOME/.microsoft-webauth/auth-file.json"
53
76
  fi
54
77
 
55
78
  # The subcommand, when the caller did not give one.
@@ -73,7 +96,7 @@ case "$SUBCOMMAND" in
73
96
  ;;
74
97
  esac
75
98
 
76
- if [ $# -eq 0 ] && [ "$SUBCOMMAND" = "export" ]; then
99
+ if [ "$SUBCOMMAND" = "export" ] && [ $# -eq 0 ]; then
77
100
  echo "Usage: $0 [--export] --notebook <name> | --notebook-link <url> [options...]" >&2
78
101
  echo "" >&2
79
102
  echo "Example:" >&2
@@ -84,11 +107,6 @@ if [ $# -eq 0 ] && [ "$SUBCOMMAND" = "export" ]; then
84
107
  exit 1
85
108
  fi
86
109
 
87
- if [ $# -eq 0 ]; then
88
- echo "Usage: $0 <$SUBCOMMAND> [options...]" >&2
89
- exit 1
90
- fi
91
-
92
110
  # One of these two must be present for a non-interactive export, and finding out
93
111
  # here rather than inside the container is the difference between an explanation
94
112
  # and `error: unknown option '--notebook-link'`.
@@ -109,6 +127,41 @@ if [ "$SUBCOMMAND" = "export" ]; then
109
127
  fi
110
128
  fi
111
129
 
130
+ # logout does not need a container.
131
+ #
132
+ # The obvious approach - mount the session read-write and let the container delete
133
+ # it - cannot work. Docker mounts a single file at /data/auth/session.json, and a
134
+ # container cannot remove a mount point: the file is the mount, so unlinking it
135
+ # fails with EACCES whether the mount is read-only or not. Making it writable
136
+ # changed nothing except how far the error got.
137
+ #
138
+ # Deleting the session is a host-side operation - one file plus its -meta.json -
139
+ # and there is nothing for the container to do. So it is done here, before any
140
+ # image is required, which also means `./start-container.sh logout` works before
141
+ # the image has ever been built.
142
+ if [ "$SUBCOMMAND" = "logout" ]; then
143
+ if [ ! -f "$AUTH_FILE" ]; then
144
+ echo "ERROR: no auth file at $AUTH_FILE" >&2
145
+ echo " Nothing to sign out of; the file is already gone." >&2
146
+ exit 1
147
+ fi
148
+
149
+ echo "Removing $AUTH_FILE"
150
+ rm -f "$AUTH_FILE"
151
+
152
+ # webauth writes the metadata beside the session as <name>-meta.json, and
153
+ # logout removes both. Leaving it behind would leave a record of the account
154
+ # with no session to go with it.
155
+ META_FILE="${AUTH_FILE%.json}-meta.json"
156
+ if [ -f "$META_FILE" ]; then
157
+ echo "Removing $META_FILE"
158
+ rm -f "$META_FILE"
159
+ fi
160
+
161
+ echo "logout finished."
162
+ exit 0
163
+ fi
164
+
112
165
  # The container name is derived from the working directory, so it is stable across
113
166
  # runs on the same machine - which means the second run collides with the first.
114
167
  # Docker refuses to reuse a name, and the error it gives ("Conflict ... already in
@@ -276,14 +329,25 @@ wait "$WATCHDOG_PID" 2>/dev/null || true
276
329
 
277
330
  echo ""
278
331
  if [ "$EXIT_CODE" -eq 0 ]; then
279
- echo "Exported files are in: $OUTPUT_DIR_ABS"
332
+ if [ "$SUBCOMMAND" = "export" ]; then
333
+ echo "Exported files are in: $OUTPUT_DIR_ABS"
334
+ else
335
+ echo "$SUBCOMMAND finished."
336
+ fi
280
337
  else
338
+ # The messages name the subcommand rather than always saying "the export": a
339
+ # failed logout reporting "the export failed and produced nothing usable"
340
+ # sends you looking for notes that were never the point of the command.
281
341
  case "$EXIT_CODE" in
282
342
  1)
283
- echo "WARNING: the export failed and produced nothing usable." >&2
343
+ echo "WARNING: $SUBCOMMAND failed." >&2
284
344
  ;;
285
345
  2)
286
- echo "WARNING: the arguments were wrong - check --notebook or --notebook-link." >&2
346
+ if [ "$SUBCOMMAND" = "export" ]; then
347
+ echo "WARNING: the arguments were wrong - check --notebook or --notebook-link." >&2
348
+ else
349
+ echo "WARNING: the arguments were wrong." >&2
350
+ fi
287
351
  ;;
288
352
  3)
289
353
  echo "NOTE: the export finished but some pages, sections or groups are missing." >&2
@@ -294,8 +358,12 @@ else
294
358
  echo "WARNING: the container exited with status $EXIT_CODE." >&2
295
359
  ;;
296
360
  esac
297
- echo "Anything already written to $OUTPUT_DIR_ABS has been kept." >&2
298
- echo "See logs/app.log inside the output directory for the full run." >&2
361
+ if [ "$SUBCOMMAND" = "export" ]; then
362
+ echo "Anything already written to $OUTPUT_DIR_ABS has been kept." >&2
363
+ echo "See logs/app.log inside the output directory for the full run." >&2
364
+ else
365
+ echo "See logs/app.log inside the output directory for the full run." >&2
366
+ fi
299
367
  fi
300
368
 
301
369
  exit "$EXIT_CODE"