You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(AppKit): trim Files skill to defer reference data to upstream docs
Align with the jobs.md/lakebase.md style: keep gotchas and idioms
in-skill, push encyclopedic reference to `npx @databricks/appkit docs`.
- Flatten Access Policies subsections (5 H3s → 0)
- Drop Policy inputs types block (duplicate of upstream `## Types`)
- Drop standalone SP-bypass snippet (mention inline instead)
- Inline Execution defaults table as a single sentence in
Server-Side API
- Drop full HTTP Routes table; keep the 403/security gotchas
- Add `npx @databricks/appkit docs` pointers from each trimmed
section (defer-to-docs count: 2 → 5, matching jobs.md)
Net effect: 410 → 346 lines (-15%); the policy concepts and
HTTP-route execution model stay, the redundant tables go.
Co-authored-by: Isaac
A `FilePolicy` is `(action, resource, user) => boolean | Promise<boolean>`. `READ_ACTIONS` and `WRITE_ACTIONS` are exported `Set<FileAction>` for action-class checks.
103
+
A `FilePolicy` is `(action, resource, user) => boolean | Promise<boolean>`. Exported `READ_ACTIONS` / `WRITE_ACTIONS` are `Set<FileAction>` for action-class checks. `user.id` comes from the `x-forwarded-user` header (HTTP) or `req` (`asUser(req)`); `user.isServicePrincipal === true` when the programmatic API skipped `asUser()`. Full `FileAction` / `FileResource` / `FilePolicyUser` shape: `npx @databricks/appkit docs Files plugin`.
-**Programmatic API**: denied → throws `PolicyDeniedError` (importable from `@databricks/appkit`) with `.action` and `.volumeKey` properties. Both `appkit.files("vol").list()` (SP, `isServicePrincipal: true`) and `appkit.files("vol").asUser(req).list()` (user) are gated.
119
+
**Enforcement**: HTTP denial → `403 { error: "Policy denied \"{action}\" on volume \"{volume}\"", plugin: "files" }`. Programmatic denial → throws `PolicyDeniedError` (exported from `@databricks/appkit`, has `.action` / `.volumeKey`). Both SP and `asUser(req)` calls are gated.
**Use `.asUser(req)` in route handlers.** Without it the policy sees `isServicePrincipal: true` and a warning is logged — fine for background jobs, wrong for user-driven endpoints where per-user policy decisions matter. Policy denial throws `PolicyDeniedError`.
175
137
176
-
**`VolumeAPI` methods**: `list`, `read`, `download`, `exists`, `metadata`, `preview`, `upload`, `createDirectory`, `delete`. `read()` caps files at 10 MB by default — pass `{ maxSize: <bytes> }` or use `download()` for larger files. Paths are absolute (`/Volumes/...`) or relative to the volume root; `../` and null bytes are rejected.
177
-
178
-
### Execution defaults
179
-
180
-
Every operation runs through cache/retry/timeout interceptors:
| Read | list, read, exists, metadata, preview | 60 s | 3× | 30 s |
185
-
| Download | download, raw | — | 3× | 30 s |
186
-
| Write | upload, mkdir, delete | — | — | 600 s |
187
-
188
-
Cache keys include the volume key (no cross-volume collisions). Write operations auto-invalidate the parent directory's cached `list` entry.
138
+
**`VolumeAPI` methods**: `list`, `read`, `download`, `exists`, `metadata`, `preview`, `upload`, `createDirectory`, `delete`. `read()` caps files at 10 MB by default — pass `{ maxSize: <bytes> }` or use `download()` for larger files. Paths are absolute (`/Volumes/...`) or relative to the volume root; `../` and null bytes are rejected. Reads cache 60 s with 3 retries; writes have a 600 s timeout, no retry, no cache; cache keys include the volume key, and writes auto-invalidate the parent directory's `list` cache. Full method signatures: `npx @databricks/appkit docs Files plugin`.
189
139
190
140
## HTTP Routes
191
141
192
-
Mounted at `/api/files/*`. All routes execute as the service principal; user identity is read from the `x-forwarded-user` header and passed to the volume's policy. Policy denial → `403`.
| GET |`/:volumeKey/list?path=`| Directory listing |
198
-
| GET |`/:volumeKey/read?path=`| Read text content |
199
-
| GET |`/:volumeKey/download?path=`| Binary stream (attachment) |
200
-
| GET |`/:volumeKey/raw?path=`| Inline stream (attachment for unsafe MIME) |
201
-
| GET |`/:volumeKey/exists?path=`| Existence check |
202
-
| GET |`/:volumeKey/metadata?path=`| File metadata |
203
-
| GET |`/:volumeKey/preview?path=`| Preview (text + type flags) |
204
-
| POST |`/:volumeKey/upload?path=`| Upload (raw body) |
205
-
| POST |`/:volumeKey/mkdir`| Create directory (`body.path`) |
206
-
| DELETE |`/:volumeKey?path=`| Delete file |
207
-
208
-
Path validation: non-empty, ≤ 4096 chars, no null bytes, no `../`. The `/raw` endpoint sets `X-Content-Type-Options: nosniff` and `Content-Security-Policy: sandbox`; HTML/JS/SVG MIME types are forced to attachment.
142
+
Mounted at `/api/files/*`. All routes execute as the service principal; user identity is read from the `x-forwarded-user` header and passed to the volume's policy (denial → `403`). Reads are GET (`list`, `read`, `download`, `raw`, `exists`, `metadata`, `preview`); writes are POST (`upload`, `mkdir`) and DELETE — full route shape, request bodies, and response types: `npx @databricks/appkit docs Files plugin`.
143
+
144
+
The `/raw` endpoint sets `X-Content-Type-Options: nosniff` and `Content-Security-Policy: sandbox`; HTML/JS/SVG MIME types are forced to attachment.
0 commit comments