Skip to content

Commit fc1a3fe

Browse files
committed
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
1 parent 7e95540 commit fc1a3fe

1 file changed

Lines changed: 11 additions & 75 deletions

File tree

  • skills/databricks-apps/references/appkit

skills/databricks-apps/references/appkit/files.md

Lines changed: 11 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -90,71 +90,33 @@ files({
9090
});
9191
```
9292

93-
### Built-in policies
93+
Built-in policies:
9494

9595
| Helper | Allows |
9696
| --------------------------- | ------------------------------------------------------------------ |
9797
| `files.policy.publicRead()` | `list`, `read`, `download`, `raw`, `exists`, `metadata`, `preview` |
9898
| `files.policy.allowAll()` | every action |
9999
| `files.policy.denyAll()` | no action (yes — even `list`) |
100100

101-
### Combinators
101+
Combinators: `policy.all(...)` (AND, short-circuits on deny), `policy.any(...)` (OR, short-circuits on allow), `policy.not(p)` (e.g. `not(publicRead())` = write-only drop-box).
102102

103-
- `files.policy.all(p1, p2, ...)` — AND, short-circuits on first deny
104-
- `files.policy.any(p1, p2, ...)` — OR, short-circuits on first allow
105-
- `files.policy.not(p)` — invert (e.g. `not(publicRead())` = write-only drop-box)
106-
107-
### Custom policies
108-
109-
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`.
110104

111105
```typescript
112106
import { type FilePolicy, WRITE_ACTIONS } from "@databricks/appkit";
113107

114108
const ADMIN_IDS = ["admin@company.com"];
115109

110+
// Writes admin-only; reads open. Wrap with `policy.any(spBypass, adminWrite)` for SP bypass.
116111
const adminWrite: FilePolicy = (action, _resource, user) => {
117112
if (WRITE_ACTIONS.has(action)) return ADMIN_IDS.includes(user.id);
118-
return true; // reads open to everyone
113+
return true;
119114
};
120115

121-
files({
122-
volumes: { reports: { policy: adminWrite } },
123-
});
116+
files({ volumes: { reports: { policy: adminWrite } } });
124117
```
125118

126-
Mix custom logic with built-ins via combinators — e.g. SP can do anything, users can only read:
127-
128-
```typescript
129-
files.policy.any(
130-
(_action, _resource, user) => !!user.isServicePrincipal,
131-
files.policy.publicRead(),
132-
);
133-
```
134-
135-
### Policy inputs
136-
137-
```typescript
138-
type FileAction =
139-
| "list" | "read" | "download" | "raw" | "exists" | "metadata" | "preview"
140-
| "upload" | "mkdir" | "delete";
141-
142-
interface FileResource {
143-
path: string; // relative path within the volume
144-
volume: string; // volume key
145-
size?: number; // content-length in bytes (uploads only)
146-
}
147-
148-
interface FilePolicyUser {
149-
id: string; // from `x-forwarded-user` header (HTTP) or req
150-
isServicePrincipal?: boolean; // true when programmatic API skipped asUser()
151-
}
152-
```
153-
154-
### Enforcement
155-
156-
- **HTTP routes**: denied → `403 { error: "Policy denied \"{action}\" on volume \"{volume}\"", plugin: "files" }`.
157-
- **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.
158120

159121
## Server-Side API (Programmatic)
160122

@@ -173,39 +135,13 @@ await appkit.files.volume("uploads").asUser(req).list();
173135

174136
**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`.
175137

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:
181-
182-
| Tier | Operations | Cache | Retry | Timeout |
183-
| -------- | ------------------------------------- | ----- | ----- | ------- |
184-
| Read | list, read, exists, metadata, preview | 60 s || 30 s |
185-
| Download | download, raw ||| 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`.
189139

190140
## HTTP Routes
191141

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`.
193-
194-
| Method | Path | Purpose |
195-
| ------ | ---------------------------- | ------------------------------------------ |
196-
| GET | `/volumes` | List configured volume keys |
197-
| 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.
209145

210146
## Frontend Components
211147

0 commit comments

Comments
 (0)