bcbd1bdb22
Integ / changes (push) Has been skipped
Pre-commit / pre-commit (push) Failing after 1s
CLI exit codes / changes (push) Has been skipped
Test (Install) / changes (push) Has been skipped
Test (Python) / changes (push) Has been skipped
Test (TypeScript) / changes (push) Has been skipped
CLI exit codes / cli-gate (push) Has been cancelled
Test (Install) / test-install-gate (push) Has been cancelled
Integ / integ-gate (push) Has been cancelled
Test (Python) / test-python-gate (push) Has been cancelled
Test (TypeScript) / test-typescript-gate (push) Has been cancelled
Test (Install) / python-minimal (3.12) (push) Has been cancelled
Test (Install) / python-minimal (3.11) (push) Has been cancelled
Test (Install) / python-extra (agno, mirage.agents.agno) (push) Has been cancelled
Test (Install) / python-extra (chroma, mirage.resource.chroma) (push) Has been cancelled
Test (Install) / python-extra (pdf, mirage.core.filetype.pdf) (push) Has been cancelled
Integ / integ (push) Has been cancelled
Integ / integ-database (push) Has been cancelled
Integ / integ-database-ts (push) Has been cancelled
Integ / integ-data (push) Has been cancelled
Integ / integ-ssh (push) Has been cancelled
Integ / integ-ssh-ts (push) Has been cancelled
Test (Python) / audit (push) Has been cancelled
Test (TypeScript) / test (push) Has been cancelled
Test (TypeScript) / python-fs-shim (push) Has been cancelled
CLI exit codes / Python CLI (push) Has been cancelled
CLI exit codes / TypeScript CLI (push) Has been cancelled
CLI exit codes / Cross-language snapshot interop (push) Has been cancelled
Test (Python) / test (push) Has been cancelled
Test (Python) / import-isolation (deepagents, openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Python) / import-isolation (deepagents, pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Integ / integ-ts (push) Has been cancelled
Integ / integ-fuse (push) Has been cancelled
Test (Install) / python-extra (databricks, mirage.resource.databricks_volume) (push) Has been cancelled
Test (Install) / python-extra (deepagents, mirage.agents.langchain) (push) Has been cancelled
Test (Install) / python-extra (email, mirage.resource.email) (push) Has been cancelled
Test (Install) / python-extra (fuse, mirage.fuse.mount) (push) Has been cancelled
Test (Install) / python-extra (hdf5, mirage.core.filetype.hdf5) (push) Has been cancelled
Test (Install) / python-extra (hf, mirage.resource.hf_buckets) (push) Has been cancelled
Test (Install) / python-extra (lancedb, mirage.resource.lancedb) (push) Has been cancelled
Test (Install) / python-extra (langfuse, mirage.resource.langfuse) (push) Has been cancelled
Test (Install) / python-extra (mongodb, mirage.resource.mongodb) (push) Has been cancelled
Test (Install) / python-extra (nextcloud, mirage.resource.nextcloud) (push) Has been cancelled
Test (Install) / python-extra (openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Install) / python-extra (openhands, mirage.agents.openhands, 3.12) (push) Has been cancelled
Test (Install) / python-extra (parquet, mirage.core.filetype.parquet) (push) Has been cancelled
Test (Install) / python-extra (postgres, mirage.resource.postgres) (push) Has been cancelled
Test (Install) / python-extra (pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Test (Install) / python-extra (qdrant, mirage.resource.qdrant) (push) Has been cancelled
Test (Install) / python-extra (redis, mirage.resource.redis) (push) Has been cancelled
Test (Install) / python-extra (s3, mirage.resource.s3) (push) Has been cancelled
Test (Install) / python-extra (ssh, mirage.resource.ssh) (push) Has been cancelled
Test (Install) / ts-minimal (push) Has been cancelled
138 lines
5.4 KiB
Plaintext
138 lines
5.4 KiB
Plaintext
---
|
|
title: Dropbox
|
|
icon: dropbox
|
|
description: Mount Dropbox as a MIRAGE resource from Node or the browser via OAuth2.
|
|
---
|
|
|
|
Mirage ships `DropboxResource` in **two runtimes**:
|
|
|
|
- `@struktoai/mirage-node`, uses `client_id` + `client_secret` + long-lived refresh token to fetch
|
|
short-lived access tokens server-side.
|
|
- `@struktoai/mirage-browser`, supports the same refresh token via PKCE (no client secret in the bundle).
|
|
|
|
Both runtimes hit the same [Dropbox v2 HTTP API](https://www.dropbox.com/developers/documentation/http/documentation):
|
|
`/2/files/list_folder` for directories, `/2/files/download` for content, and `/2/files/search_v2`
|
|
for search. Credentials are obtained the same way in both runtimes, see
|
|
[Dropbox Credentials](/home/setup/dropbox).
|
|
|
|
## Node (server-side)
|
|
|
|
```bash
|
|
pnpm add @struktoai/mirage-node
|
|
```
|
|
|
|
```ts
|
|
import { DropboxResource, MountMode, Workspace } from '@struktoai/mirage-node'
|
|
|
|
const dropbox = new DropboxResource({
|
|
clientId: process.env.DROPBOX_APP_KEY!,
|
|
clientSecret: process.env.DROPBOX_APP_SECRET!,
|
|
refreshToken: process.env.DROPBOX_REFRESH_TOKEN!,
|
|
})
|
|
|
|
const ws = new Workspace({ '/dropbox': dropbox }, { mode: MountMode.READ })
|
|
const res = await ws.execute('ls /dropbox/')
|
|
console.log(res.stdoutText)
|
|
```
|
|
|
|
The `DropboxTokenManager` caches the access token in memory and refreshes it ~5 minutes before
|
|
expiry, so cold-start API calls don't pay the refresh round-trip.
|
|
|
|
## Browser (PKCE, no client secret)
|
|
|
|
```bash
|
|
pnpm add @struktoai/mirage-browser
|
|
```
|
|
|
|
```ts
|
|
import { DropboxResource, MountMode, Workspace } from '@struktoai/mirage-browser'
|
|
|
|
// Refresh token obtained via the PKCE flow, see examples/typescript/browser/src/dropbox_pkce.ts.
|
|
const dropbox = new DropboxResource({
|
|
clientId: import.meta.env.VITE_DROPBOX_APP_KEY,
|
|
refreshToken: refreshTokenFromLocalStorage,
|
|
})
|
|
|
|
const ws = new Workspace({ '/dropbox': dropbox }, { mode: MountMode.READ })
|
|
await ws.execute('ls /dropbox/')
|
|
```
|
|
|
|
Set the redirect URI on your Dropbox app's **Settings** tab to your dev/prod origin
|
|
(e.g. `http://localhost:5173/dropbox_pkce.html`). The bundled
|
|
[`examples/typescript/browser/src/dropbox_pkce.ts`](https://github.com/strukto-ai/mirage/blob/main/examples/typescript/browser/src/dropbox_pkce.ts)
|
|
runs the full PKCE dance end-to-end and persists the refresh token to `localStorage`.
|
|
|
|
## VFS mode (`patchNodeFs`)
|
|
|
|
Mirage exposes a `patchNodeFs(workspace)` shim that routes `fs.promises.*` calls under a mount
|
|
through the workspace, so any library that uses Node's `fs` API can read directly from Dropbox
|
|
without code changes.
|
|
|
|
```ts
|
|
import { createRequire } from 'node:module'
|
|
import { DropboxResource, MountMode, patchNodeFs, Workspace } from '@struktoai/mirage-node'
|
|
|
|
const require = createRequire(import.meta.url)
|
|
const fs = require('fs') as typeof import('fs')
|
|
|
|
const ws = new Workspace({ '/dropbox': dropbox }, { mode: MountMode.READ })
|
|
const restore = patchNodeFs(ws)
|
|
|
|
const entries = await fs.promises.readdir('/dropbox/')
|
|
const stat = await fs.promises.stat('/dropbox/data')
|
|
const bytes = await fs.promises.readFile('/dropbox/data/example.parquet')
|
|
|
|
restore()
|
|
```
|
|
|
|
Only `fs.promises.*` (the async API) is patched. Sync forms like `fs.statSync` and
|
|
`fs.readFileSync` aren't supported because remote reads can't block the event loop.
|
|
|
|
## FUSE mode
|
|
|
|
For tools that need a real filesystem path (CLI tools, editors, system utilities), mount the
|
|
workspace under FUSE:
|
|
|
|
```ts
|
|
import { DropboxResource, Mount, MountMode, Workspace } from '@struktoai/mirage-node'
|
|
|
|
const ws = new Workspace({ '/dropbox': new Mount(dropbox, { mode: MountMode.READ, fuse: true }) })
|
|
await ws.fuseReady()
|
|
const mp = ws.fuseMountpoint
|
|
|
|
// The dropbox subtree is exposed at the mountpoint root, so `${mp}/` is a real path:
|
|
// ls ${mp}/
|
|
// find ${mp} -name '*.parquet'
|
|
// cat ${mp}/data/example.json | jq .
|
|
|
|
await ws.close()
|
|
```
|
|
|
|
Requires [macFUSE](https://osxfuse.github.io/) on macOS or libfuse on Linux. See
|
|
[FUSE setup](/home/setup/macos).
|
|
|
|
## Available commands
|
|
|
|
`DropboxResource` ships the same shell command set as the GDrive resource:
|
|
|
|
- **Filesystem**: `ls`, `cat`, `head`, `tail`, `nl`, `wc`, `stat`, `find`, `tree`, `du`, `file`,
|
|
`realpath`, `basename`, `dirname`
|
|
- **Search/text**: `grep`, `rg`, `awk`, `sed`, `sort`, `uniq`, `cut`, `diff`, `cmp`, `jq`
|
|
- **Encoding**: `base64`
|
|
- **Format-aware**: `cat_parquet`, `cat_feather`, `cat_hdf5`, `head_parquet`, `head_feather`,
|
|
`head_hdf5`, `cut_*`, `grep_*`, `ls_*`, `stat_*`, `tail_*`, `wc_*`, `file_*` for `.parquet`,
|
|
`.feather`, `.hdf5`/`.h5`, `.orc` files
|
|
|
|
The format-aware commands transparently decode binary tabular files, so
|
|
`cat /dropbox/data/example.parquet` returns a column preview instead of binary garbage.
|
|
|
|
## Examples
|
|
|
|
End-to-end runnable scripts are in
|
|
[`examples/typescript/dropbox/`](https://github.com/strukto-ai/mirage/tree/main/examples/typescript/dropbox):
|
|
|
|
- [`dropbox.ts`](https://github.com/strukto-ai/mirage/blob/main/examples/typescript/dropbox/dropbox.ts), `Workspace.execute('ls/stat/cat/tree …')` shell demo
|
|
- [`dropbox_parquet.ts`](https://github.com/strukto-ai/mirage/blob/main/examples/typescript/dropbox/dropbox_parquet.ts), parquet preview through `cat`
|
|
- [`dropbox_vfs.ts`](https://github.com/strukto-ai/mirage/blob/main/examples/typescript/dropbox/dropbox_vfs.ts), `patchNodeFs` + native `fs.promises.*` calls
|
|
- [`dropbox_fuse.ts`](https://github.com/strukto-ai/mirage/blob/main/examples/typescript/dropbox/dropbox_fuse.ts), FUSE mount with shell access in another terminal
|