@seliseblocks/cli-os 0.2.9 → 0.2.11
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/AI_USAGE_GUIDE.md +560 -560
- package/LICENSE +21 -21
- package/README.md +173 -173
- package/bin/run.js +2 -2
- package/dist/commands/auth/oidc-clients/save.js +4 -1
- package/dist/commands/data/rules/pull.js +1 -1
- package/dist/commands/new/web.js +3 -2
- package/dist/index.js +699 -698
- package/dist/lib/data-files.d.ts +6 -1
- package/dist/lib/data-files.js +9 -2
- package/dist/lib/oidc-discovery.d.ts +2 -0
- package/dist/lib/oidc-discovery.js +12 -0
- package/dist/skills/blocks-data-gateway-configuration/SKILL.md +204 -204
- package/dist/skills/blocks-data-gateway-crud/SKILL.md +223 -223
- package/dist/skills/blocks-data-storage/SKILL.md +253 -253
- package/dist/skills/blocks-data-storage/flows/object-management.md +124 -124
- package/dist/skills/blocks-frontend-local-https/SKILL.md +100 -100
- package/dist/skills/blocks-iam-account/SKILL.md +169 -169
- package/dist/skills/blocks-iam-sso-oidc-configuration/SKILL.md +2 -2
- package/dist/skills/blocks-iam-sso-oidc-implementation/SKILL.md +80 -80
- package/dist/skills/blocks-iam-users/SKILL.md +131 -131
- package/dist/skills/blocks-localization-configuration/SKILL.md +149 -149
- package/dist/skills/blocks-localization-implementation/SKILL.md +63 -63
- package/dist/skills/blocks-onboarding/SKILL.md +72 -72
- package/dist/skills/blocks-storage-configuration/SKILL.md +93 -93
- package/package.json +47 -47
|
@@ -1,253 +1,253 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: blocks-data-storage
|
|
3
|
-
description: "Build file and document-management features on SELISE Blocks Data: upload/download, directory trees, cursor-paginated browsing and search, file versions, rename/move/copy, soft delete/trash/restore, sharing, access policies, and inheritance. Use for attachments, file browsers, folders, shared files, permissions, or version history. Use 'blocks data files *' for terminal/admin work and @seliseblocks/client data.files/data.directories/data.objects for app code."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Blocks Data — Storage
|
|
7
|
-
|
|
8
|
-
Treat storage as one permission-aware object tree containing **directories** and **files**. Uploading a new file now creates the file object in that tree; there is no second DMS registration step.
|
|
9
|
-
|
|
10
|
-
Use:
|
|
11
|
-
|
|
12
|
-
- **`blocks data files *`** for supported terminal/admin operations.
|
|
13
|
-
- **`@seliseblocks/client`** for app code. Use the shared `blocksClient` created by blocks-onboarding.
|
|
14
|
-
- **blocks-storage-configuration** only to manage the named provider configuration used by `configurationName`.
|
|
15
|
-
|
|
16
|
-
Select a project first with `blocks use <tenantId>`. If login/project state or the shared client setup is unknown, use blocks-onboarding before this skill.
|
|
17
|
-
|
|
18
|
-
Store the returned `fileId` in a Data record when attaching a file to domain data. Use blocks-data-gateway-crud for the record mutation.
|
|
19
|
-
|
|
20
|
-
## Choose the surface
|
|
21
|
-
|
|
22
|
-
The current CLI and SDK follow the backend's file, directory, and object resource groups.
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
blocks --version
|
|
26
|
-
blocks data files --help
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
- Use `blocks data files *` for terminal/admin work and inspect `blocks --help` for exact flags.
|
|
30
|
-
- Use `blocksClient.data.files` for bytes, metadata, versions, and file operations.
|
|
31
|
-
- Use `blocksClient.data.directories` for directory create/get/update/delete/move.
|
|
32
|
-
- Use `blocksClient.data.objects` for browse/search/trash/shared/restore/share/access/inheritance.
|
|
33
|
-
|
|
34
|
-
Legacy `data.dms.*`, `dms-upload`, `dms-list`, `create-folder`, and `delete-folder` wrappers are retired. Uploads need no registration call.
|
|
35
|
-
|
|
36
|
-
## Upload a new file
|
|
37
|
-
|
|
38
|
-
Choose one path from the project's storage configuration.
|
|
39
|
-
|
|
40
|
-
| Provider category | Sequence |
|
|
41
|
-
|---|---|
|
|
42
|
-
| Cloud object storage | request a pre-signed URL, then PUT the bytes to it |
|
|
43
|
-
| Local/SFTP storage | send one authenticated multipart upload |
|
|
44
|
-
|
|
45
|
-
Both paths create the file object and initial version directly. Do not call `dms-upload` afterward.
|
|
46
|
-
|
|
47
|
-
### Cloud upload from the CLI
|
|
48
|
-
|
|
49
|
-
Prefer the composed command. It previews and confirms both metadata creation and the provider PUT:
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
blocks data files upload --file ./invoice.pdf --parent-id <directoryId> \
|
|
53
|
-
--configuration-name Default --access-modifier Private --dry-run --json
|
|
54
|
-
blocks data files upload --file ./invoice.pdf --parent-id <directoryId> \
|
|
55
|
-
--configuration-name Default --access-modifier Private --yes --json
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Use the two explicit commands only when the intermediate upload URL is required:
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
blocks data files presigned-upload-url \
|
|
62
|
-
--name invoice.pdf \
|
|
63
|
-
--parent-directory-id <directoryId> \
|
|
64
|
-
--configuration-name Default \
|
|
65
|
-
--access-modifier Private \
|
|
66
|
-
--dry-run --json
|
|
67
|
-
blocks data files presigned-upload-url \
|
|
68
|
-
--name invoice.pdf \
|
|
69
|
-
--parent-directory-id <directoryId> \
|
|
70
|
-
--configuration-name Default \
|
|
71
|
-
--access-modifier Private \
|
|
72
|
-
--yes --json
|
|
73
|
-
|
|
74
|
-
blocks data files upload-to-url \
|
|
75
|
-
--url "<uploadUrl>" \
|
|
76
|
-
--file ./invoice.pdf \
|
|
77
|
-
--content-type application/pdf \
|
|
78
|
-
--dry-run --json
|
|
79
|
-
blocks data files upload-to-url \
|
|
80
|
-
--url "<uploadUrl>" \
|
|
81
|
-
--file ./invoice.pdf \
|
|
82
|
-
--content-type application/pdf \
|
|
83
|
-
--yes --json
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
The presign response contains `uploadUrl`, `fileId`, and `isSuccess`. The first call creates the file metadata/version; the PUT fills its object-storage key. Handle PUT failure explicitly because it can leave metadata for missing bytes.
|
|
87
|
-
|
|
88
|
-
When `parentDirectoryId` is empty, the cloud upload resolves `moduleName` to that module's default directory. The backend default is module value `8` (`Default_Construct`), but pass the intended module or a concrete directory id instead of relying on that default.
|
|
89
|
-
|
|
90
|
-
### Cloud upload from app code
|
|
91
|
-
|
|
92
|
-
```ts
|
|
93
|
-
const presign = await blocksClient.data.files.presignedUploadUrl({
|
|
94
|
-
name: "invoice.pdf",
|
|
95
|
-
parentDirectoryId: directoryId,
|
|
96
|
-
configurationName: "Default",
|
|
97
|
-
accessModifier: "Private",
|
|
98
|
-
tags: "invoice,2026",
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
if (!presign || typeof presign !== "object") {
|
|
102
|
-
throw new Error("Unexpected upload response");
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const result = presign as {
|
|
106
|
-
uploadUrl: string;
|
|
107
|
-
fileId: string;
|
|
108
|
-
isSuccess: boolean;
|
|
109
|
-
errors?: Record<string, string>;
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
if (!result.isSuccess) throw new Error(JSON.stringify(result.errors));
|
|
113
|
-
|
|
114
|
-
await blocksClient.data.files.uploadToUrl({
|
|
115
|
-
url: result.uploadUrl,
|
|
116
|
-
body: file,
|
|
117
|
-
contentType: file.type || "application/octet-stream",
|
|
118
|
-
});
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
`uploadToUrl` is provider-direct and sends no bearer token or `x-blocks-key`. The SDK adds Azure's `x-ms-blob-type: Blockblob` header unless overridden; ensure that header matches the signed provider policy.
|
|
122
|
-
|
|
123
|
-
### Local-storage upload
|
|
124
|
-
|
|
125
|
-
```bash
|
|
126
|
-
blocks data files upload-to-local-storage \
|
|
127
|
-
--file ./invoice.pdf \
|
|
128
|
-
--parent-directory-id <directoryId> \
|
|
129
|
-
--configuration-name Default \
|
|
130
|
-
--access-modifier Private \
|
|
131
|
-
--dry-run --json
|
|
132
|
-
blocks data files upload-to-local-storage \
|
|
133
|
-
--file ./invoice.pdf \
|
|
134
|
-
--parent-directory-id <directoryId> \
|
|
135
|
-
--configuration-name Default \
|
|
136
|
-
--access-modifier Private \
|
|
137
|
-
--yes --json
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
```ts
|
|
141
|
-
const uploaded = await blocksClient.data.files.uploadToLocalStorage({
|
|
142
|
-
name: file.name,
|
|
143
|
-
file,
|
|
144
|
-
parentDirectoryId: directoryId,
|
|
145
|
-
configurationName: "Default",
|
|
146
|
-
accessModifier: "Private",
|
|
147
|
-
tags: ["invoice", "2026"],
|
|
148
|
-
});
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
This call creates the file object and uploads version 1 in one request. Unlike cloud presign, an empty local `parentDirectoryId` stays at the top level; it is not resolved through `moduleName`.
|
|
152
|
-
|
|
153
|
-
## Add a file version
|
|
154
|
-
|
|
155
|
-
Supplying an existing `itemId` to either upload flow creates another version after the caller passes the file's Edit check. For cloud storage, the dedicated command/method returns another pre-signed URL:
|
|
156
|
-
|
|
157
|
-
```bash
|
|
158
|
-
blocks data files versions <fileId> --limit 25 --json
|
|
159
|
-
blocks data files create-version <fileId> --configuration-name Default --dry-run --json
|
|
160
|
-
blocks data files create-version <fileId> --configuration-name Default --yes --json
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
```ts
|
|
164
|
-
const history = await blocksClient.data.files.versions({ fileId, limit: 25 });
|
|
165
|
-
const next = await blocksClient.data.files.createVersion({ fileId, configurationName: "Default" });
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
Version history is newest-first and cursor-paginated. Use the returned opaque `nextCursor`; the current backend uses the last version number internally, but callers must not construct cursors. Limits are 1–100, default 25.
|
|
169
|
-
|
|
170
|
-
## Read and download
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
blocks data files get <fileId> --configuration-name Default --json
|
|
174
|
-
blocks data files get <fileId> --version <versionNo> --configuration-name Default --json
|
|
175
|
-
blocks data files get-many <fileId...> --configuration-name Default --json
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
```ts
|
|
179
|
-
const file = await blocksClient.data.files.get(fileId, {
|
|
180
|
-
configurationName: "Default",
|
|
181
|
-
version: 2,
|
|
182
|
-
});
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
The response includes a download URL plus metadata. Download requires the caller's Download permission. Access-denied reads may deliberately look like missing resources so clients cannot probe hidden object ids.
|
|
186
|
-
|
|
187
|
-
## Directory and object workflows
|
|
188
|
-
|
|
189
|
-
For browsing, directories, search, move/copy/rename, trash, sharing, and ACL behavior, read [flows/object-management.md](flows/object-management.md).
|
|
190
|
-
|
|
191
|
-
## Update custom metadata
|
|
192
|
-
|
|
193
|
-
```bash
|
|
194
|
-
blocks data files update-additional-info <fileId> \
|
|
195
|
-
--additional-properties '{"status":"reviewed"}' \
|
|
196
|
-
--dry-run --json
|
|
197
|
-
blocks data files update-additional-info <fileId> \
|
|
198
|
-
--additional-properties '{"status":"reviewed"}' \
|
|
199
|
-
--yes --json
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
This updates `additionalProperties`; it does not rename, move, tag, or version the file.
|
|
203
|
-
|
|
204
|
-
## Delete safely
|
|
205
|
-
|
|
206
|
-
Deletion now distinguishes trash from permanent removal:
|
|
207
|
-
|
|
208
|
-
- `permanent: false` archives the file or directory so it can be restored.
|
|
209
|
-
- `permanent: true` removes it for good.
|
|
210
|
-
- The backend default is **`true`** when `permanent` is omitted.
|
|
211
|
-
|
|
212
|
-
The CLI defaults to safe soft deletion. Add `--permanent` only after explicit approval.
|
|
213
|
-
|
|
214
|
-
```bash
|
|
215
|
-
blocks data files delete <fileId> --dry-run --json
|
|
216
|
-
blocks data files delete <fileId> --yes --json
|
|
217
|
-
blocks data files delete <fileId> --permanent --dry-run --json
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
In app code, send the choice explicitly: `blocksClient.data.files.delete({ fileId, permanent: false })`.
|
|
221
|
-
|
|
222
|
-
## Permission model
|
|
223
|
-
|
|
224
|
-
Every storage request passes two checks:
|
|
225
|
-
|
|
226
|
-
1. The endpoint permission permits that class of action.
|
|
227
|
-
2. The object ACL permits the action on that specific file/directory.
|
|
228
|
-
|
|
229
|
-
Capabilities are ordered: `View`, `Download`, `Edit`, `Delete`, `Manage`, `Owner`. Higher capabilities imply lower ones. Directory children inherit ancestor access while `inheritsParentAccess` is true. New files inherit from their directory.
|
|
230
|
-
|
|
231
|
-
Do not infer permission from a visible button or endpoint grant. Render actions from each object's returned `permissions` flags and still handle 403/404 races.
|
|
232
|
-
|
|
233
|
-
## Gotchas
|
|
234
|
-
|
|
235
|
-
- Upload now creates the visible file object; legacy DMS registration is wrong and may fail after the bytes were successfully PUT.
|
|
236
|
-
- Cloud presign creates metadata before the provider PUT. Treat the two steps as a recoverable workflow and surface partial failure.
|
|
237
|
-
- A name must contain an allowed extension. Directories may restrict extensions.
|
|
238
|
-
- Names are unique within a directory. File move/copy can fail on a name conflict or extension policy.
|
|
239
|
-
- `Private` is the safe default. Use `Public` only when unauthenticated download is intended.
|
|
240
|
-
- `configurationName` selects an existing provider record; it does not configure storage.
|
|
241
|
-
- Most legacy file SDK methods return `Promise<unknown>`; validate responses at the boundary.
|
|
242
|
-
- Never send Blocks auth headers to a pre-signed provider URL.
|
|
243
|
-
- Never use a raw API call to work around a missing CLI/SDK wrapper; update the client surface first.
|
|
244
|
-
|
|
245
|
-
## Example triggers
|
|
246
|
-
|
|
247
|
-
- "Upload this PDF into the Contracts folder."
|
|
248
|
-
- "Build a file browser with folders and search."
|
|
249
|
-
- "Show files shared with the current user."
|
|
250
|
-
- "Move this file to trash and let users restore it."
|
|
251
|
-
- "Add version history and upload a replacement version."
|
|
252
|
-
- "Share this directory with a role and let its children inherit access."
|
|
253
|
-
- "Move, copy, or rename a file."
|
|
1
|
+
---
|
|
2
|
+
name: blocks-data-storage
|
|
3
|
+
description: "Build file and document-management features on SELISE Blocks Data: upload/download, directory trees, cursor-paginated browsing and search, file versions, rename/move/copy, soft delete/trash/restore, sharing, access policies, and inheritance. Use for attachments, file browsers, folders, shared files, permissions, or version history. Use 'blocks data files *' for terminal/admin work and @seliseblocks/client data.files/data.directories/data.objects for app code."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Blocks Data — Storage
|
|
7
|
+
|
|
8
|
+
Treat storage as one permission-aware object tree containing **directories** and **files**. Uploading a new file now creates the file object in that tree; there is no second DMS registration step.
|
|
9
|
+
|
|
10
|
+
Use:
|
|
11
|
+
|
|
12
|
+
- **`blocks data files *`** for supported terminal/admin operations.
|
|
13
|
+
- **`@seliseblocks/client`** for app code. Use the shared `blocksClient` created by blocks-onboarding.
|
|
14
|
+
- **blocks-storage-configuration** only to manage the named provider configuration used by `configurationName`.
|
|
15
|
+
|
|
16
|
+
Select a project first with `blocks use <tenantId>`. If login/project state or the shared client setup is unknown, use blocks-onboarding before this skill.
|
|
17
|
+
|
|
18
|
+
Store the returned `fileId` in a Data record when attaching a file to domain data. Use blocks-data-gateway-crud for the record mutation.
|
|
19
|
+
|
|
20
|
+
## Choose the surface
|
|
21
|
+
|
|
22
|
+
The current CLI and SDK follow the backend's file, directory, and object resource groups.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
blocks --version
|
|
26
|
+
blocks data files --help
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- Use `blocks data files *` for terminal/admin work and inspect `blocks --help` for exact flags.
|
|
30
|
+
- Use `blocksClient.data.files` for bytes, metadata, versions, and file operations.
|
|
31
|
+
- Use `blocksClient.data.directories` for directory create/get/update/delete/move.
|
|
32
|
+
- Use `blocksClient.data.objects` for browse/search/trash/shared/restore/share/access/inheritance.
|
|
33
|
+
|
|
34
|
+
Legacy `data.dms.*`, `dms-upload`, `dms-list`, `create-folder`, and `delete-folder` wrappers are retired. Uploads need no registration call.
|
|
35
|
+
|
|
36
|
+
## Upload a new file
|
|
37
|
+
|
|
38
|
+
Choose one path from the project's storage configuration.
|
|
39
|
+
|
|
40
|
+
| Provider category | Sequence |
|
|
41
|
+
|---|---|
|
|
42
|
+
| Cloud object storage | request a pre-signed URL, then PUT the bytes to it |
|
|
43
|
+
| Local/SFTP storage | send one authenticated multipart upload |
|
|
44
|
+
|
|
45
|
+
Both paths create the file object and initial version directly. Do not call `dms-upload` afterward.
|
|
46
|
+
|
|
47
|
+
### Cloud upload from the CLI
|
|
48
|
+
|
|
49
|
+
Prefer the composed command. It previews and confirms both metadata creation and the provider PUT:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
blocks data files upload --file ./invoice.pdf --parent-id <directoryId> \
|
|
53
|
+
--configuration-name Default --access-modifier Private --dry-run --json
|
|
54
|
+
blocks data files upload --file ./invoice.pdf --parent-id <directoryId> \
|
|
55
|
+
--configuration-name Default --access-modifier Private --yes --json
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Use the two explicit commands only when the intermediate upload URL is required:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
blocks data files presigned-upload-url \
|
|
62
|
+
--name invoice.pdf \
|
|
63
|
+
--parent-directory-id <directoryId> \
|
|
64
|
+
--configuration-name Default \
|
|
65
|
+
--access-modifier Private \
|
|
66
|
+
--dry-run --json
|
|
67
|
+
blocks data files presigned-upload-url \
|
|
68
|
+
--name invoice.pdf \
|
|
69
|
+
--parent-directory-id <directoryId> \
|
|
70
|
+
--configuration-name Default \
|
|
71
|
+
--access-modifier Private \
|
|
72
|
+
--yes --json
|
|
73
|
+
|
|
74
|
+
blocks data files upload-to-url \
|
|
75
|
+
--url "<uploadUrl>" \
|
|
76
|
+
--file ./invoice.pdf \
|
|
77
|
+
--content-type application/pdf \
|
|
78
|
+
--dry-run --json
|
|
79
|
+
blocks data files upload-to-url \
|
|
80
|
+
--url "<uploadUrl>" \
|
|
81
|
+
--file ./invoice.pdf \
|
|
82
|
+
--content-type application/pdf \
|
|
83
|
+
--yes --json
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The presign response contains `uploadUrl`, `fileId`, and `isSuccess`. The first call creates the file metadata/version; the PUT fills its object-storage key. Handle PUT failure explicitly because it can leave metadata for missing bytes.
|
|
87
|
+
|
|
88
|
+
When `parentDirectoryId` is empty, the cloud upload resolves `moduleName` to that module's default directory. The backend default is module value `8` (`Default_Construct`), but pass the intended module or a concrete directory id instead of relying on that default.
|
|
89
|
+
|
|
90
|
+
### Cloud upload from app code
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
const presign = await blocksClient.data.files.presignedUploadUrl({
|
|
94
|
+
name: "invoice.pdf",
|
|
95
|
+
parentDirectoryId: directoryId,
|
|
96
|
+
configurationName: "Default",
|
|
97
|
+
accessModifier: "Private",
|
|
98
|
+
tags: "invoice,2026",
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (!presign || typeof presign !== "object") {
|
|
102
|
+
throw new Error("Unexpected upload response");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const result = presign as {
|
|
106
|
+
uploadUrl: string;
|
|
107
|
+
fileId: string;
|
|
108
|
+
isSuccess: boolean;
|
|
109
|
+
errors?: Record<string, string>;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
if (!result.isSuccess) throw new Error(JSON.stringify(result.errors));
|
|
113
|
+
|
|
114
|
+
await blocksClient.data.files.uploadToUrl({
|
|
115
|
+
url: result.uploadUrl,
|
|
116
|
+
body: file,
|
|
117
|
+
contentType: file.type || "application/octet-stream",
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`uploadToUrl` is provider-direct and sends no bearer token or `x-blocks-key`. The SDK adds Azure's `x-ms-blob-type: Blockblob` header unless overridden; ensure that header matches the signed provider policy.
|
|
122
|
+
|
|
123
|
+
### Local-storage upload
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
blocks data files upload-to-local-storage \
|
|
127
|
+
--file ./invoice.pdf \
|
|
128
|
+
--parent-directory-id <directoryId> \
|
|
129
|
+
--configuration-name Default \
|
|
130
|
+
--access-modifier Private \
|
|
131
|
+
--dry-run --json
|
|
132
|
+
blocks data files upload-to-local-storage \
|
|
133
|
+
--file ./invoice.pdf \
|
|
134
|
+
--parent-directory-id <directoryId> \
|
|
135
|
+
--configuration-name Default \
|
|
136
|
+
--access-modifier Private \
|
|
137
|
+
--yes --json
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
const uploaded = await blocksClient.data.files.uploadToLocalStorage({
|
|
142
|
+
name: file.name,
|
|
143
|
+
file,
|
|
144
|
+
parentDirectoryId: directoryId,
|
|
145
|
+
configurationName: "Default",
|
|
146
|
+
accessModifier: "Private",
|
|
147
|
+
tags: ["invoice", "2026"],
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
This call creates the file object and uploads version 1 in one request. Unlike cloud presign, an empty local `parentDirectoryId` stays at the top level; it is not resolved through `moduleName`.
|
|
152
|
+
|
|
153
|
+
## Add a file version
|
|
154
|
+
|
|
155
|
+
Supplying an existing `itemId` to either upload flow creates another version after the caller passes the file's Edit check. For cloud storage, the dedicated command/method returns another pre-signed URL:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
blocks data files versions <fileId> --limit 25 --json
|
|
159
|
+
blocks data files create-version <fileId> --configuration-name Default --dry-run --json
|
|
160
|
+
blocks data files create-version <fileId> --configuration-name Default --yes --json
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
const history = await blocksClient.data.files.versions({ fileId, limit: 25 });
|
|
165
|
+
const next = await blocksClient.data.files.createVersion({ fileId, configurationName: "Default" });
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Version history is newest-first and cursor-paginated. Use the returned opaque `nextCursor`; the current backend uses the last version number internally, but callers must not construct cursors. Limits are 1–100, default 25.
|
|
169
|
+
|
|
170
|
+
## Read and download
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
blocks data files get <fileId> --configuration-name Default --json
|
|
174
|
+
blocks data files get <fileId> --version <versionNo> --configuration-name Default --json
|
|
175
|
+
blocks data files get-many <fileId...> --configuration-name Default --json
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
const file = await blocksClient.data.files.get(fileId, {
|
|
180
|
+
configurationName: "Default",
|
|
181
|
+
version: 2,
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
The response includes a download URL plus metadata. Download requires the caller's Download permission. Access-denied reads may deliberately look like missing resources so clients cannot probe hidden object ids.
|
|
186
|
+
|
|
187
|
+
## Directory and object workflows
|
|
188
|
+
|
|
189
|
+
For browsing, directories, search, move/copy/rename, trash, sharing, and ACL behavior, read [flows/object-management.md](flows/object-management.md).
|
|
190
|
+
|
|
191
|
+
## Update custom metadata
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
blocks data files update-additional-info <fileId> \
|
|
195
|
+
--additional-properties '{"status":"reviewed"}' \
|
|
196
|
+
--dry-run --json
|
|
197
|
+
blocks data files update-additional-info <fileId> \
|
|
198
|
+
--additional-properties '{"status":"reviewed"}' \
|
|
199
|
+
--yes --json
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
This updates `additionalProperties`; it does not rename, move, tag, or version the file.
|
|
203
|
+
|
|
204
|
+
## Delete safely
|
|
205
|
+
|
|
206
|
+
Deletion now distinguishes trash from permanent removal:
|
|
207
|
+
|
|
208
|
+
- `permanent: false` archives the file or directory so it can be restored.
|
|
209
|
+
- `permanent: true` removes it for good.
|
|
210
|
+
- The backend default is **`true`** when `permanent` is omitted.
|
|
211
|
+
|
|
212
|
+
The CLI defaults to safe soft deletion. Add `--permanent` only after explicit approval.
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
blocks data files delete <fileId> --dry-run --json
|
|
216
|
+
blocks data files delete <fileId> --yes --json
|
|
217
|
+
blocks data files delete <fileId> --permanent --dry-run --json
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
In app code, send the choice explicitly: `blocksClient.data.files.delete({ fileId, permanent: false })`.
|
|
221
|
+
|
|
222
|
+
## Permission model
|
|
223
|
+
|
|
224
|
+
Every storage request passes two checks:
|
|
225
|
+
|
|
226
|
+
1. The endpoint permission permits that class of action.
|
|
227
|
+
2. The object ACL permits the action on that specific file/directory.
|
|
228
|
+
|
|
229
|
+
Capabilities are ordered: `View`, `Download`, `Edit`, `Delete`, `Manage`, `Owner`. Higher capabilities imply lower ones. Directory children inherit ancestor access while `inheritsParentAccess` is true. New files inherit from their directory.
|
|
230
|
+
|
|
231
|
+
Do not infer permission from a visible button or endpoint grant. Render actions from each object's returned `permissions` flags and still handle 403/404 races.
|
|
232
|
+
|
|
233
|
+
## Gotchas
|
|
234
|
+
|
|
235
|
+
- Upload now creates the visible file object; legacy DMS registration is wrong and may fail after the bytes were successfully PUT.
|
|
236
|
+
- Cloud presign creates metadata before the provider PUT. Treat the two steps as a recoverable workflow and surface partial failure.
|
|
237
|
+
- A name must contain an allowed extension. Directories may restrict extensions.
|
|
238
|
+
- Names are unique within a directory. File move/copy can fail on a name conflict or extension policy.
|
|
239
|
+
- `Private` is the safe default. Use `Public` only when unauthenticated download is intended.
|
|
240
|
+
- `configurationName` selects an existing provider record; it does not configure storage.
|
|
241
|
+
- Most legacy file SDK methods return `Promise<unknown>`; validate responses at the boundary.
|
|
242
|
+
- Never send Blocks auth headers to a pre-signed provider URL.
|
|
243
|
+
- Never use a raw API call to work around a missing CLI/SDK wrapper; update the client surface first.
|
|
244
|
+
|
|
245
|
+
## Example triggers
|
|
246
|
+
|
|
247
|
+
- "Upload this PDF into the Contracts folder."
|
|
248
|
+
- "Build a file browser with folders and search."
|
|
249
|
+
- "Show files shared with the current user."
|
|
250
|
+
- "Move this file to trash and let users restore it."
|
|
251
|
+
- "Add version history and upload a replacement version."
|
|
252
|
+
- "Share this directory with a role and let its children inherit access."
|
|
253
|
+
- "Move, copy, or rename a file."
|