Skip to content

fix: list and traverse folders shared with you (closes #7) - #55

Open
lionello wants to merge 2 commits into
masterfrom
fix-shared-folders
Open

fix: list and traverse folders shared with you (closes #7)#55
lionello wants to merge 2 commits into
masterfrom
fix-shared-folders

Conversation

@lionello

@lionello lionello commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Fixes #7, plus the release-blocking lint failure found along the way.

Shared folders (d16b1c3)

A folder shared with you is a stub on your drive carrying a remoteItem facet — the real item lives on the owner's drive. That is why stat worked (the stub is a real item) while ls reported no children (the stub genuinely has none), and why nothing below it resolved by path.

sanitize() could only build /drive/root:/…: paths, so there was no way to address an item on another drive. Three new primitives sit next to it:

itemAddress() addresses an item as /drives/{driveId}/items/{itemId}, following remoteItem to the target on the owner's drive
resolveShared() for a path below a stub, walks down from the top; the first ancestor with a remoteItem is the stub, and the remainder is addressed relative to it
withShared() retry wrapper — only fires after a 404, so ordinary paths cost nothing extra
resolveFolder() eager resolve for child enumeration, the one case that can't be detected from a failure: listing a stub's children succeeds and returns nothing

Item-relative path addressing off an item id is documented for exactly this case: "when working with shared folders, you can use a path-based URL relative to the shared folder's item ID".

Applied to ls, find, cp -R, cat, stat, rm, mv, mkdir, wget, upload and the MCP list/find/read tools.

Also fixes the second symptom noted in the issue: is_folder() and the ls columns now read through remoteItem, so a shared folder lists as a folder with its owner and child count instead of as an empty file.

Recursive traversal in find/cp -R now tracks the display path as it descends rather than deriving it from parentReference.path — a child on someone else's drive reports a parent path that isn't addressable from our drive.

chmod/ln/sendmail are deliberately left alone: they are owner-side sharing operations, not meaningful on someone else's drive.

ESLint flat config (e997228)

Independent of #7, but it blocks releases, so it is here as its own commit: the v1.4.0 publish never reached npm. package-lock.json pins ESLint 10.8.0, which since v9 only reads eslint.config.js, so npm ci && npm run lint exited 2 before npm publish.

  • .eslintrc.jseslint.config.js, with @eslint/js and globals added as devDeps (ESLint 10 no longer bundles either).
  • bin/onedrive is listed explicitly in files: flat config only lints files a pattern matches, and it has no .js extension. Without it eslint reports "File ignored because no matching configuration was supplied" and exits 0 — a lint step that lints nothing.
  • ESLint 9 also started applying no-unused-vars to caught errors, flagging four catch blocks that deliberately ignore the error. Unused bindings dropped (optional catch binding; engines already requires Node >= 18) rather than weakening the rule.

To actually ship 1.4.0, re-running the failed job won't help — it checks out the v1.4.0 tag, which predates this. Either move the tag after merging (package.json still says 1.4.0, so the version-match step passes) or cut 1.4.1.

Testing

The saved token here was expired, so I could not hit the live API. Instead I built a mock of the classic API with a shared folder on it and ran the CLI against it. Verified working: ls of the stub and of folders below it, cat at any depth, stat, find with -name/-type, cp -R (correct contents and local tree), mkdir/rm/mv reaching the owner's drive, and the MCP helpers. Missing paths still fail cleanly in a bounded number of requests. Diffing old vs new output on non-shared paths shows no output changes — only the extra resolve GET and id-based recursion.

npm run lint exits 0 against ESLint 10.8.0 and prettier is clean.

Worth a check against a real shared folder before merging: resolveShared()'s item-relative addressing is the one piece verified only against docs and the mock.

🤖 Generated with Claude Code

lionello and others added 2 commits August 3, 2026 15:32
The v1.4.0 publish never reached npm: package-lock.json pins ESLint
10.8.0, which (since v9) only reads eslint.config.js, so `npm ci && npm
run lint` in the release workflow died with "ESLint couldn't find an
eslint.config.(js|mjs|cjs) file" and exit 2.

Port .eslintrc.js to flat config. ESLint 10 no longer bundles @eslint/js
or globals, so both are declared as devDependencies. bin/onedrive has no
.js extension and flat config only lints files matched by a `files`
pattern, so it is listed explicitly -- without it eslint reports "File
ignored because no matching configuration was supplied" and exits 0,
i.e. a lint step that lints nothing.

ESLint 9 also started applying no-unused-vars to caught errors, which
flags four catch blocks that deliberately ignore the error. Drop the
unused bindings (optional catch binding; engines already require Node
>=18) rather than weakening the rule, and move ecmaVersion to 2022.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A folder shared with you is a stub on your drive carrying a `remoteItem`
facet; the real item lives on the owner's drive. That is why `stat`
worked (the stub is a real item) while `ls` reported no children (the
stub genuinely has none), and why nothing below it resolved by path.

sanitize() could only build /drive/root:/...: paths, so there was no way
to address an item on another drive. Add three primitives next to it:

  itemAddress()   /drives/{driveId}/items/{itemId}, following remoteItem
                  to the target on the owner's drive
  resolveShared() for a path below a stub, walk down from the top; the
                  first ancestor with a remoteItem is the stub, and the
                  remainder is addressed relative to it. Documented for
                  exactly this case, see
                  learn.microsoft.com/onedrive/developer/rest-api/concepts/addressing-driveitems
  withShared()    retry wrapper; only fires after a 404, so ordinary
                  paths cost nothing extra
  resolveFolder() eager resolve for child enumeration, which is the one
                  case that cannot be detected from a failure: listing a
                  stub's children succeeds and returns nothing

Applied to ls, find, cp -R, cat, stat, rm, mv, mkdir, wget, upload and
the MCP list/find/read tools.

Also fix the second symptom: is_folder() and the ls columns now read
through remoteItem, so a shared folder lists as a folder with its owner
and child count instead of as an empty file.

Recursive traversal in find/cp -R now tracks the display path as it
descends rather than deriving it from parentReference.path: a child on
someone else's drive reports a parent path that is not addressable from
our drive.

Closes #7

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unable to list contents of a shared folder

1 participant