@seliseblocks/cli-os 0.2.2 → 0.2.4
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 +20 -15
- package/README.md +5 -5
- package/dist/commands/auth/idp/create.d.ts +7 -0
- package/dist/commands/auth/idp/create.js +22 -3
- package/dist/commands/auth/idp/update.d.ts +7 -0
- package/dist/commands/auth/idp/update.js +22 -3
- package/dist/commands/data/files/delete.js +5 -4
- package/dist/commands/data/files/get-many.js +1 -1
- package/dist/commands/data/files/get.js +1 -1
- package/dist/commands/data/files/info.js +1 -1
- package/dist/commands/data/files/object-tree.d.ts +23 -0
- package/dist/commands/data/files/object-tree.js +238 -0
- package/dist/commands/data/files/presigned-upload-url.js +9 -2
- package/dist/commands/data/files/update-additional-info.js +2 -2
- package/dist/commands/data/files/upload-to-local-storage.js +2 -2
- package/dist/commands/data/files/upload.d.ts +2 -4
- package/dist/commands/data/files/upload.js +14 -28
- package/dist/commands/new/web.js +4 -0
- package/dist/index.js +100 -42
- package/dist/skills/blocks-data-storage/SKILL.md +194 -102
- package/dist/skills/blocks-data-storage/flows/object-management.md +124 -0
- package/dist/skills/blocks-iam-sso-oidc-configuration/SKILL.md +25 -9
- package/dist/skills/blocks-onboarding/SKILL.md +2 -2
- package/dist/skills/blocks-storage-configuration/SKILL.md +93 -93
- package/package.json +1 -1
- package/dist/commands/data/files/create-folder.d.ts +0 -1
- package/dist/commands/data/files/create-folder.js +0 -34
- package/dist/commands/data/files/delete-folder.d.ts +0 -1
- package/dist/commands/data/files/delete-folder.js +0 -25
- package/dist/commands/data/files/dms-list.d.ts +0 -1
- package/dist/commands/data/files/dms-list.js +0 -27
- package/dist/commands/data/files/dms-upload.d.ts +0 -6
- package/dist/commands/data/files/dms-upload.js +0 -41
package/AI_USAGE_GUIDE.md
CHANGED
|
@@ -128,10 +128,10 @@ Then run with explicit flags so no prompt is reached:
|
|
|
128
128
|
blocks new web <appName> --x-blocks-key <projectTenantId> --app-domain <appDomainOrUrl> --client-id <publicOidcClientId>
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
-
`new web` also accepts `--blocks-api-url <url>` and `--oidc-url <url>`, same as `sdk client`
|
|
132
|
-
below. When `--blocks-api-url` is omitted, the scaffold derives it from the app domain as
|
|
133
|
-
`https://blocksapi.<registrable-domain>`; for example `https://dqrsf.slsblx.com` becomes
|
|
134
|
-
`https://blocksapi.slsblx.com`. Pass `--blocks-api-url` only when targeting a non-default Blocks gateway. `--oidc-url` defaults to `https://iam.seliseblocks.com`.
|
|
131
|
+
`new web` also accepts `--blocks-api-url <url>` and `--oidc-url <url>`, same as `sdk client`
|
|
132
|
+
below. When `--blocks-api-url` is omitted, the scaffold derives it from the app domain as
|
|
133
|
+
`https://blocksapi.<registrable-domain>`; for example `https://dqrsf.slsblx.com` becomes
|
|
134
|
+
`https://blocksapi.slsblx.com`. Pass `--blocks-api-url` only when targeting a non-default Blocks gateway. `--oidc-url` defaults to `https://iam.seliseblocks.com`.
|
|
135
135
|
|
|
136
136
|
Validate the scaffold:
|
|
137
137
|
|
|
@@ -160,10 +160,10 @@ The generated cert script uses the `selfsigned` Node dependency, so it works fro
|
|
|
160
160
|
`sdk client` answers "I want to use the Blocks SDK - show me the client." It resolves this project's `@seliseblocks/client` config (same values `new web` scaffolds an app with) and prints a ready-to-paste `createBlocksClient(...)` snippet - **it never writes a file or mutates anything**. To scaffold a full app instead, use `new web` above.
|
|
161
161
|
|
|
162
162
|
```bash
|
|
163
|
-
blocks sdk client --x-blocks-key <projectTenantId> --app-domain <appDomainOrUrl> --client-id <publicOidcClientId> --blocks-api-url https://api.seliseblocks.com
|
|
163
|
+
blocks sdk client --x-blocks-key <projectTenantId> --app-domain <appDomainOrUrl> --client-id <publicOidcClientId> --blocks-api-url https://api.seliseblocks.com
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
-
Unlike `new web`, `sdk client` keeps `--blocks-api-url` defaulted to `https://api.seliseblocks.com`; only pass it explicitly if your project uses a different gateway URL. Passing both `--app-domain` and `--client-id` skips the project lookup entirely, so it needs no CLI login at all - useful for a quick, non-interactive check. Omit either one and it resolves from the selected project instead (auto-picks when there's exactly one match, otherwise lists the options and asks you to pass the flag explicitly - it does not prompt or create anything, since this command is read-only). Use `--json` for the resolved values instead of the snippet.
|
|
166
|
+
Unlike `new web`, `sdk client` keeps `--blocks-api-url` defaulted to `https://api.seliseblocks.com`; only pass it explicitly if your project uses a different gateway URL. Passing both `--app-domain` and `--client-id` skips the project lookup entirely, so it needs no CLI login at all - useful for a quick, non-interactive check. Omit either one and it resolves from the selected project instead (auto-picks when there's exactly one match, otherwise lists the options and asks you to pass the flag explicitly - it does not prompt or create anything, since this command is read-only). Use `--json` for the resolved values instead of the snippet.
|
|
167
167
|
|
|
168
168
|
## Skills
|
|
169
169
|
|
|
@@ -181,9 +181,9 @@ Every other command below is project-scoped: it requires a project already selec
|
|
|
181
181
|
|
|
182
182
|
Command families (run `blocks --help` for the full flag reference on each):
|
|
183
183
|
|
|
184
|
-
- `iam users *`, `iam email available` - list/get/create/update/activate/deactivate, access grant/revoke, existence and email-availability checks.
|
|
185
|
-
- `iam roles *` - list/get/create/update, assign-permissions, assignable. `assign-permissions` accepts permission resource strings and resolves them to itemIds before sending IAM's id-based mutation.
|
|
186
|
-
- `iam permissions *` - list/get/create/update, by-severity.
|
|
184
|
+
- `iam users *`, `iam email available` - list/get/create/update/activate/deactivate, access grant/revoke, existence and email-availability checks.
|
|
185
|
+
- `iam roles *` - list/get/create/update, assign-permissions, assignable. `assign-permissions` accepts permission resource strings and resolves them to itemIds before sending IAM's id-based mutation.
|
|
186
|
+
- `iam permissions *` - list/get/create/update, by-severity.
|
|
187
187
|
- `iam resources *` - resource groups and feature flags (read-only).
|
|
188
188
|
- `iam organizations *` - list/get/create/update, `my`, and organization config get/save.
|
|
189
189
|
- `iam signup-settings *` - get/save tenant signup policy.
|
|
@@ -280,13 +280,13 @@ It validates first and hard-fails with no API calls made if schemas or the rules
|
|
|
280
280
|
- `data schema info list`/`save`/`update` + `data schema fields` - a two-step alternative to `schema push` (create/update schema metadata, then add/update field definitions separately). Prefer the file-oriented `schema push` workflow for normal authoring; use these only for a targeted metadata or field-only change without touching the local schema JSON.
|
|
281
281
|
- `data rules policy get`/`delete` - read or delete one data-access policy without a full `rules pull`/edit/`rules deploy` round-trip.
|
|
282
282
|
- `data validation list`/`get`/`by-schema`/`by-schema-field`/`save`/`delete` - field-level validation rules. No file-oriented workflow exists for these (no local JSON file to pull/push). `save` is an upsert (omit `--item-id` to create, pass it to update) and requires a `validations` array passed via `--body`/`--file` - there's no scalar flag for it, e.g. `--body '{"validations":[{"type":1,"value":"^[0-9]+$","isActive":true}]}'`.
|
|
283
|
-
- `data files *` -
|
|
283
|
+
- `data files *` - permission-aware storage object tree: upload/download, directory CRUD/move, cursor list/search, versions, copy/move/rename, trash/restore/purge, shared objects, and access policies/inheritance.
|
|
284
284
|
|
|
285
285
|
Same rules as everywhere else: `--dry-run` before any mutating command, then `--yes` only after explicit approval.
|
|
286
286
|
|
|
287
287
|
**`--file` means two different things depending on the command.** Everywhere else in this CLI (`--body '<json>'`/`--file <path.json>`), `--file` is a JSON payload file read by `jsonBodyFlag`. On the `data files *` upload commands (`upload-to-url`, `upload-to-local-storage`), `--file` is instead the local binary file to read and upload - there is no JSON payload involved. Don't conflate the two: passing a JSON path to `data files upload-to-local-storage --file` uploads the JSON text as the file's bytes, it does not set a request body.
|
|
288
288
|
|
|
289
|
-
**Prefer the composed `data files upload` over the manual steps below.**
|
|
289
|
+
**Prefer the composed `data files upload` over the manual steps below.** For cloud storage it creates the file/version metadata and PUTs the bytes; for local storage it performs one multipart call. Either path creates the visible object directly—there is no DMS registration step:
|
|
290
290
|
|
|
291
291
|
```bash
|
|
292
292
|
blocks data files upload --file ./invoice.pdf --access-modifier Public --dry-run --json
|
|
@@ -297,7 +297,8 @@ blocks data files upload --file ./invoice.pdf --local-storage --yes --json # l
|
|
|
297
297
|
Manual cloud-storage upload, if you need the intermediate steps for some reason (two calls):
|
|
298
298
|
|
|
299
299
|
```bash
|
|
300
|
-
blocks data files presigned-upload-url --name invoice.pdf --access-modifier Public --json
|
|
300
|
+
blocks data files presigned-upload-url --name invoice.pdf --access-modifier Public --dry-run --json
|
|
301
|
+
blocks data files presigned-upload-url --name invoice.pdf --access-modifier Public --yes --json
|
|
301
302
|
# take the returned uploadUrl and fileId, then:
|
|
302
303
|
blocks data files upload-to-url --url "<uploadUrl>" --file ./invoice.pdf --content-type application/pdf --dry-run --json
|
|
303
304
|
blocks data files upload-to-url --url "<uploadUrl>" --file ./invoice.pdf --content-type application/pdf --yes --json
|
|
@@ -310,11 +311,15 @@ blocks data files upload-to-local-storage --file ./invoice.pdf --access-modifier
|
|
|
310
311
|
blocks data files upload-to-local-storage --file ./invoice.pdf --access-modifier Public --yes --json
|
|
311
312
|
```
|
|
312
313
|
|
|
313
|
-
|
|
314
|
+
Browse the resulting object tree with cursor pagination. Deletion defaults to trash:
|
|
314
315
|
|
|
315
316
|
```bash
|
|
316
|
-
blocks data files
|
|
317
|
-
blocks data files
|
|
317
|
+
blocks data files list --parent-id <directoryId> --limit 50 --json
|
|
318
|
+
blocks data files search invoice --directory-id <directoryId> --json
|
|
319
|
+
blocks data files delete <fileId> --dry-run --json
|
|
320
|
+
blocks data files delete <fileId> --yes --json
|
|
321
|
+
blocks data files trash --json
|
|
322
|
+
blocks data files restore <fileId> --dry-run --json
|
|
318
323
|
```
|
|
319
324
|
|
|
320
325
|
## Localization
|
package/README.md
CHANGED
|
@@ -84,8 +84,8 @@ Global options available on every command:
|
|
|
84
84
|
| `blocks data schema get/get-by-name/aggregation/change-logs/delete/fields/info *` | Raw `/data/v4/schemas*` API beyond the file-oriented `list/pull/push` above: single-schema/by-name lookups, access-level aggregation, unadapted change logs, delete, and a metadata-first (`info *`) plus field-only (`fields`) alternative to `push`. Run `blocks --help` for the full flag reference. |
|
|
85
85
|
| `blocks data rules policy get/delete` | Single data-access policy read/delete via `/data/v4/data-access/policy/*`, alongside the bulk file-oriented `rules pull/deploy` above. |
|
|
86
86
|
| `blocks data validation list/get/by-schema/by-schema-field/save/delete` | Field-level validation rules via `/data/v4/data-validations*`. No file-oriented workflow exists for this yet; `save` is an upsert (omit `--item-id` to create) and requires a `validations` array via `--body`/`--file`. |
|
|
87
|
-
| `blocks data files upload --file <path> [--local-storage]` | Composed upload:
|
|
88
|
-
| `blocks data files *` | Full
|
|
87
|
+
| `blocks data files upload --file <path> [--local-storage]` | Composed upload: cloud storage creates the file/version record and PUTs the bytes; local storage uses one multipart request. The file is immediately part of the object tree—there is no DMS registration step. |
|
|
88
|
+
| `blocks data files *` | Full storage object-tree surface: file get/upload/metadata/delete/version/copy/move/rename, directory CRUD/move, cursor-paginated list/search/shared/trash, restore/purge, and access policy/share/inheritance commands. Delete defaults to trash; pass `--permanent` explicitly to remove data. Run `blocks --help` for flags. |
|
|
89
89
|
| `blocks localization validate --module <name> --language <culture> [--file <path>] [--json]` | Validate a local i18n JSON dictionary. Supports nested JSON input and checks the flattened key/value set locally. |
|
|
90
90
|
| `blocks localization push --module <name> --language <culture> [--file <path>] [--route <route>] [--context <text>] [--dry-run] [--yes] [--json]` | Create or update Localization keys from local i18n JSON via `/localization/v4/Key/SaveKeys`. Creates the module first through `/localization/v4/Module/Save` when missing. |
|
|
91
91
|
| `blocks localization pull --module <name> --language <culture> [--out <path>] [--json]` | Download published cloud localization via `/localization/v4/Key/GetCloudUilmFile` and write a local JSON dictionary. |
|
|
@@ -95,9 +95,9 @@ Global options available on every command:
|
|
|
95
95
|
| `blocks release status <buildId> [--json]` | Read Release build status by build id. Read-only. |
|
|
96
96
|
| `blocks release builds list [repoId] [--repo-id <repoId>] [--json]` | List Release build details for a repository. When `repoId` is omitted, resolves it from the selected project's linked repo assets - auto-picked if there's exactly one, otherwise you're prompted to choose. Read-only. |
|
|
97
97
|
| `blocks release builds get <buildId> [--json]` | Alias for `release status`. Read-only. |
|
|
98
|
-
| `blocks new web <name> [--app-domain <domain>] [--client-id <oidcClientId>] [--x-blocks-key <tenantId>] [--blocks-api-url <url>] [--oidc-url <url>]` | Create a Vite React starter app that talks to Blocks exclusively through `@seliseblocks/client` (a single `createBlocksClient()` instance) using the SDK hosted IdP flow: `blocksClient.auth.idp.redirectToProvider()` on login click and `blocksClient.auth.idp.callback()` on `/login/callback`. Includes route guards, auto-refresh through `auth.oidc.refreshToken()`, live `auth`/`iam`/`data`/`localization` SDK examples, environment config, and safe `.gitignore` defaults. Uses the selected project (see `use`) unless `--x-blocks-key` overrides it. `--app-domain` and `--client-id` are resolved from the project record when omitted: the domain auto-picks if the project has exactly one, otherwise you're prompted to choose; the OIDC client is picked from the project's existing clients, or you can create a minimal one (display name + redirect URI) on the spot, or skip and register one later from the portal or `auth oidc-clients save`. When `--blocks-api-url` is omitted, `new web` derives it from the app domain as `https://blocksapi.<registrable-domain>`; for example `https://dqrsf.slsblx.com` becomes `https://blocksapi.slsblx.com`. Pass a different Data/IAM/Localization/OS gateway URL explicitly only if your project uses a non-default one. `--oidc-url` defaults to `https://iam.seliseblocks.com`. |
|
|
98
|
+
| `blocks new web <name> [--app-domain <domain>] [--client-id <oidcClientId>] [--x-blocks-key <tenantId>] [--blocks-api-url <url>] [--oidc-url <url>]` | Create a Vite React starter app that talks to Blocks exclusively through `@seliseblocks/client` (a single `createBlocksClient()` instance) using the SDK hosted IdP flow: `blocksClient.auth.idp.redirectToProvider()` on login click and `blocksClient.auth.idp.callback()` on `/login/callback`. Includes route guards, auto-refresh through `auth.oidc.refreshToken()`, live `auth`/`iam`/`data`/`localization` SDK examples, environment config, and safe `.gitignore` defaults. Uses the selected project (see `use`) unless `--x-blocks-key` overrides it. `--app-domain` and `--client-id` are resolved from the project record when omitted: the domain auto-picks if the project has exactly one, otherwise you're prompted to choose; the OIDC client is picked from the project's existing clients, or you can create a minimal one (display name + redirect URI) on the spot, or skip and register one later from the portal or `auth oidc-clients save`. When `--blocks-api-url` is omitted, `new web` derives it from the app domain as `https://blocksapi.<registrable-domain>`; for example `https://dqrsf.slsblx.com` becomes `https://blocksapi.slsblx.com`. Pass a different Data/IAM/Localization/OS gateway URL explicitly only if your project uses a non-default one. `--oidc-url` defaults to `https://iam.seliseblocks.com`. |
|
|
99
99
|
| `blocks skill list [--json]` / `skill show <name> [--json]` / `skill add <name> [--dir <path>]` | Local-only, no cloud calls: list/print the bundled `blocks-skills/*/SKILL.md` agent context docs, or copy a skill's entire directory (`SKILL.md` plus any supporting files) into `<dir>/<name>/` (default `./blocks-skills`) for use in a project outside this monorepo. `list`'s output and `show`/`add`'s "unknown skill" error both point at the full public skill catalog in case the bundled set is out of date. |
|
|
100
|
-
| `blocks sdk client [--app-domain <domain>] [--client-id <oidcClientId>] [--x-blocks-key <tenantId>] [--blocks-api-url <url>] [--oidc-url <url>] [--json]` | Read-only: resolves this project's `@seliseblocks/client` config and prints a ready-to-paste `createBlocksClient(...)` snippet. Unlike `new web`, the API URL defaults to `https://api.seliseblocks.com` unless `--blocks-api-url` is passed. Passing both `--app-domain` and `--client-id` skips the project lookup entirely (no login required). Writes nothing - use `new web` to scaffold a full app. |
|
|
100
|
+
| `blocks sdk client [--app-domain <domain>] [--client-id <oidcClientId>] [--x-blocks-key <tenantId>] [--blocks-api-url <url>] [--oidc-url <url>] [--json]` | Read-only: resolves this project's `@seliseblocks/client` config and prints a ready-to-paste `createBlocksClient(...)` snippet. Unlike `new web`, the API URL defaults to `https://api.seliseblocks.com` unless `--blocks-api-url` is passed. Passing both `--app-domain` and `--client-id` skips the project lookup entirely (no login required). Writes nothing - use `new web` to scaffold a full app. |
|
|
101
101
|
|
|
102
102
|
Use `--json` on commands when AI or automation needs machine-readable output. Use `--dry-run` before mutations and `--yes` only after approval.
|
|
103
103
|
|
|
@@ -166,7 +166,7 @@ Localization dictionaries are not created by `init` - the default path is `block
|
|
|
166
166
|
## Boundaries
|
|
167
167
|
|
|
168
168
|
- `iam me` reads the CLI operator's own account identity; every other `iam *`, `mfa *`, `auth idp *`/`auth config *`/`auth client-credentials *`/`auth oidc-clients *`, `mail *`, `notification *`, `notifier *`, `secrets *`, and `storage config *` command is project-scoped and requires a selected project (`blocks use <tenantId>`) plus an impersonated project token - none of them ever run against the account token.
|
|
169
|
-
- Data covers
|
|
169
|
+
- Data covers tenant data-source configuration, schema/rules/reload/validate, field-level validation rules, and the storage object tree (`data files *`). Prefer the composed `data sync` and `data files upload` workflows.
|
|
170
170
|
- Localization covers dictionary validate/pull/push plus the full raw `/localization/v4/*` API surface (assistant, config, glossary, key, language, module). Prefer `localization key translate-and-export` over running translate/generate/export by hand.
|
|
171
171
|
- Release covers deploy trigger and build status/read commands only.
|
|
172
172
|
- No direct artifact upload unless Blocks Release adds a confirmed artifact upload API.
|
|
@@ -1 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The endpoint URLs are not decoration: `GET /iam/v4/idp/initiate` builds the
|
|
3
|
+
* provider authorize URL from the stored `authorizationUrl` and falls back to an
|
|
4
|
+
* empty base when it is missing, so a provider saved without it hands the browser
|
|
5
|
+
* a bare query string. Apple-only fields (teamId/keyId/privateKey/appleAudience)
|
|
6
|
+
* stay in --body/--file so no private key lands in shell history.
|
|
7
|
+
*/
|
|
1
8
|
export declare function authIdpCreate(argv: string[]): Promise<void>;
|
|
@@ -1,25 +1,44 @@
|
|
|
1
|
-
import { booleanFlag, stringFlag } from "../../../lib/args.js";
|
|
1
|
+
import { booleanFlag, optionalBooleanFlag, stringFlag } from "../../../lib/args.js";
|
|
2
2
|
import { blocksRequest } from "../../../lib/api.js";
|
|
3
3
|
import { confirmMutation } from "../../../lib/confirm.js";
|
|
4
4
|
import { compact, jsonBodyFlag, listFlag } from "../../../lib/json-flag.js";
|
|
5
5
|
import { writeOutput } from "../../../lib/output.js";
|
|
6
6
|
import { requestContext } from "../../../lib/request-context.js";
|
|
7
7
|
import { parseCommand, selectedProject } from "../../../lib/workspace.js";
|
|
8
|
+
/**
|
|
9
|
+
* The endpoint URLs are not decoration: `GET /iam/v4/idp/initiate` builds the
|
|
10
|
+
* provider authorize URL from the stored `authorizationUrl` and falls back to an
|
|
11
|
+
* empty base when it is missing, so a provider saved without it hands the browser
|
|
12
|
+
* a bare query string. Apple-only fields (teamId/keyId/privateKey/appleAudience)
|
|
13
|
+
* stay in --body/--file so no private key lands in shell history.
|
|
14
|
+
*/
|
|
8
15
|
export async function authIdpCreate(argv) {
|
|
9
16
|
const { flags } = parseCommand(argv);
|
|
10
17
|
const body = {
|
|
11
18
|
...(await jsonBodyFlag(flags)),
|
|
12
19
|
...compact({
|
|
20
|
+
authorizationUrl: stringFlag(flags, "authorization-url") || undefined,
|
|
13
21
|
clientId: stringFlag(flags, "client-id") || undefined,
|
|
14
22
|
clientSecret: stringFlag(flags, "client-secret") || undefined,
|
|
15
23
|
displayName: stringFlag(flags, "display-name") || undefined,
|
|
16
|
-
|
|
24
|
+
grantTypes: listFlag(flags, "grant-types"),
|
|
25
|
+
icon: stringFlag(flags, "icon") || undefined,
|
|
26
|
+
initialPermissions: listFlag(flags, "initial-permissions"),
|
|
27
|
+
initialRoles: listFlag(flags, "initial-roles"),
|
|
28
|
+
isActive: optionalBooleanFlag(flags, "active"),
|
|
17
29
|
issuer: stringFlag(flags, "issuer") || undefined,
|
|
30
|
+
jwksUri: stringFlag(flags, "jwks-uri") || undefined,
|
|
18
31
|
protocol: stringFlag(flags, "protocol") || undefined,
|
|
19
32
|
provider: stringFlag(flags, "provider") || undefined,
|
|
20
33
|
providerType: stringFlag(flags, "provider-type") || undefined,
|
|
21
34
|
redirectUris: listFlag(flags, "redirect-uris"),
|
|
22
|
-
|
|
35
|
+
requirePkce: optionalBooleanFlag(flags, "require-pkce"),
|
|
36
|
+
responseType: stringFlag(flags, "response-type") || undefined,
|
|
37
|
+
scope: stringFlag(flags, "scope") || undefined,
|
|
38
|
+
tokenEndpointAuthMethod: stringFlag(flags, "token-endpoint-auth-method") || undefined,
|
|
39
|
+
tokenUrl: stringFlag(flags, "token-url") || undefined,
|
|
40
|
+
userInfoUrl: stringFlag(flags, "user-info-url") || undefined,
|
|
41
|
+
wellKnownUrl: stringFlag(flags, "well-known-url") || undefined
|
|
23
42
|
})
|
|
24
43
|
};
|
|
25
44
|
if (!body.provider || !body.providerType || !body.protocol || !body.clientId) {
|
|
@@ -3,5 +3,12 @@
|
|
|
3
3
|
* IAM requires them to echo the existing value when supplied, so only pass them
|
|
4
4
|
* via --provider/--provider-type/--protocol/--client-id if you're re-sending the
|
|
5
5
|
* current configuration alongside other field changes.
|
|
6
|
+
*
|
|
7
|
+
* This is also the only endpoint that can set the OIDC endpoint URLs: the create
|
|
8
|
+
* endpoint silently drops authorizationUrl/tokenUrl/userInfoUrl, and a provider
|
|
9
|
+
* auto-registered from an OIDC client (--register-as-identity-provider) never has
|
|
10
|
+
* them. `GET /iam/v4/idp/initiate` needs authorizationUrl, so a freshly created
|
|
11
|
+
* provider has to be patched here before hosted login works. Apple-only fields
|
|
12
|
+
* stay in --body/--file so no private key lands in shell history.
|
|
6
13
|
*/
|
|
7
14
|
export declare function authIdpUpdate(argv: string[]): Promise<void>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { booleanFlag, stringFlag } from "../../../lib/args.js";
|
|
1
|
+
import { booleanFlag, optionalBooleanFlag, stringFlag } from "../../../lib/args.js";
|
|
2
2
|
import { blocksRequest } from "../../../lib/api.js";
|
|
3
3
|
import { confirmMutation } from "../../../lib/confirm.js";
|
|
4
4
|
import { compact, jsonBodyFlag, listFlag } from "../../../lib/json-flag.js";
|
|
@@ -10,6 +10,13 @@ import { parseCommand, selectedProject } from "../../../lib/workspace.js";
|
|
|
10
10
|
* IAM requires them to echo the existing value when supplied, so only pass them
|
|
11
11
|
* via --provider/--provider-type/--protocol/--client-id if you're re-sending the
|
|
12
12
|
* current configuration alongside other field changes.
|
|
13
|
+
*
|
|
14
|
+
* This is also the only endpoint that can set the OIDC endpoint URLs: the create
|
|
15
|
+
* endpoint silently drops authorizationUrl/tokenUrl/userInfoUrl, and a provider
|
|
16
|
+
* auto-registered from an OIDC client (--register-as-identity-provider) never has
|
|
17
|
+
* them. `GET /iam/v4/idp/initiate` needs authorizationUrl, so a freshly created
|
|
18
|
+
* provider has to be patched here before hosted login works. Apple-only fields
|
|
19
|
+
* stay in --body/--file so no private key lands in shell history.
|
|
13
20
|
*/
|
|
14
21
|
export async function authIdpUpdate(argv) {
|
|
15
22
|
const { args, flags } = parseCommand(argv);
|
|
@@ -17,15 +24,27 @@ export async function authIdpUpdate(argv) {
|
|
|
17
24
|
const body = {
|
|
18
25
|
...(await jsonBodyFlag(flags)),
|
|
19
26
|
...compact({
|
|
27
|
+
authorizationUrl: stringFlag(flags, "authorization-url") || undefined,
|
|
20
28
|
clientId: stringFlag(flags, "client-id") || undefined,
|
|
21
29
|
displayName: stringFlag(flags, "display-name") || undefined,
|
|
22
|
-
|
|
30
|
+
grantTypes: listFlag(flags, "grant-types"),
|
|
31
|
+
icon: stringFlag(flags, "icon") || undefined,
|
|
32
|
+
initialPermissions: listFlag(flags, "initial-permissions"),
|
|
33
|
+
initialRoles: listFlag(flags, "initial-roles"),
|
|
34
|
+
isActive: optionalBooleanFlag(flags, "active"),
|
|
23
35
|
issuer: stringFlag(flags, "issuer") || undefined,
|
|
36
|
+
jwksUri: stringFlag(flags, "jwks-uri") || undefined,
|
|
24
37
|
protocol: stringFlag(flags, "protocol") || undefined,
|
|
25
38
|
provider: stringFlag(flags, "provider") || undefined,
|
|
26
39
|
providerType: stringFlag(flags, "provider-type") || undefined,
|
|
27
40
|
redirectUris: listFlag(flags, "redirect-uris"),
|
|
28
|
-
|
|
41
|
+
requirePkce: optionalBooleanFlag(flags, "require-pkce"),
|
|
42
|
+
responseType: stringFlag(flags, "response-type") || undefined,
|
|
43
|
+
scope: stringFlag(flags, "scope") || undefined,
|
|
44
|
+
tokenEndpointAuthMethod: stringFlag(flags, "token-endpoint-auth-method") || undefined,
|
|
45
|
+
tokenUrl: stringFlag(flags, "token-url") || undefined,
|
|
46
|
+
userInfoUrl: stringFlag(flags, "user-info-url") || undefined,
|
|
47
|
+
wellKnownUrl: stringFlag(flags, "well-known-url") || undefined
|
|
29
48
|
})
|
|
30
49
|
};
|
|
31
50
|
if (booleanFlag(flags, "dry-run")) {
|
|
@@ -8,17 +8,18 @@ import { parseCommand, selectedProject } from "../../../lib/workspace.js";
|
|
|
8
8
|
export async function dataFilesDelete(argv) {
|
|
9
9
|
const { args, flags } = parseCommand(argv);
|
|
10
10
|
const fileId = args[0] || stringFlag(flags, "file-id", { required: true });
|
|
11
|
-
const
|
|
11
|
+
const permanent = booleanFlag(flags, "permanent");
|
|
12
|
+
const body = { fileId, permanent, ...compact({
|
|
12
13
|
configurationName: stringFlag(flags, "configuration-name") || undefined,
|
|
13
14
|
eventQueueName: stringFlag(flags, "event-queue-name") || undefined
|
|
14
15
|
}) };
|
|
15
16
|
if (booleanFlag(flags, "dry-run")) {
|
|
16
|
-
writeOutput({ dryRun: true, endpoint: "/data/v4/
|
|
17
|
+
writeOutput({ dryRun: true, endpoint: "/data/v4/files/delete-file", request: body }, flags);
|
|
17
18
|
return;
|
|
18
19
|
}
|
|
19
|
-
await confirmMutation(flags,
|
|
20
|
+
await confirmMutation(flags, `${permanent ? "Permanently delete" : "Move"} file '${fileId}'${permanent ? "" : " to trash"}.`);
|
|
20
21
|
const projectKey = await selectedProject(flags);
|
|
21
|
-
const result = await blocksRequest("/data/v4/
|
|
22
|
+
const result = await blocksRequest("/data/v4/files/delete-file", {
|
|
22
23
|
body,
|
|
23
24
|
impersonatedProjectAuth: true,
|
|
24
25
|
...requestContext(flags),
|
|
@@ -14,7 +14,7 @@ export async function dataFilesGetMany(argv) {
|
|
|
14
14
|
fileIds
|
|
15
15
|
});
|
|
16
16
|
const projectKey = await selectedProject(flags);
|
|
17
|
-
const result = await blocksRequest("/data/v4/
|
|
17
|
+
const result = await blocksRequest("/data/v4/files/get-files", {
|
|
18
18
|
body,
|
|
19
19
|
impersonatedProjectAuth: true,
|
|
20
20
|
...requestContext(flags),
|
|
@@ -7,7 +7,7 @@ export async function dataFilesGet(argv) {
|
|
|
7
7
|
const { args, flags } = parseCommand(argv);
|
|
8
8
|
const fileId = args[0] || stringFlag(flags, "file-id", { required: true });
|
|
9
9
|
const projectKey = await selectedProject(flags);
|
|
10
|
-
const result = await blocksRequest("/data/v4/
|
|
10
|
+
const result = await blocksRequest("/data/v4/files/get-file", {
|
|
11
11
|
impersonatedProjectAuth: true,
|
|
12
12
|
...requestContext(flags),
|
|
13
13
|
projectTenantId: projectKey,
|
|
@@ -20,7 +20,7 @@ export async function dataFilesInfo(argv) {
|
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
22
|
const projectKey = await selectedProject(flags);
|
|
23
|
-
const result = await blocksRequest("/data/v4/
|
|
23
|
+
const result = await blocksRequest("/data/v4/files/get-files-info", {
|
|
24
24
|
body,
|
|
25
25
|
impersonatedProjectAuth: true,
|
|
26
26
|
...requestContext(flags),
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare function dataFilesList(argv: string[]): Promise<void>;
|
|
2
|
+
export declare function dataFilesSearch(argv: string[]): Promise<void>;
|
|
3
|
+
export declare function dataFilesTrash(argv: string[]): Promise<void>;
|
|
4
|
+
export declare function dataFilesShared(argv: string[]): Promise<void>;
|
|
5
|
+
export declare function dataFilesRestore(argv: string[]): Promise<void>;
|
|
6
|
+
export declare function dataFilesPurge(argv: string[]): Promise<void>;
|
|
7
|
+
export declare function dataFilesDirectoryCreate(argv: string[]): Promise<void>;
|
|
8
|
+
export declare function dataFilesDirectoryGet(argv: string[]): Promise<void>;
|
|
9
|
+
export declare function dataFilesDirectoryUpdate(argv: string[]): Promise<void>;
|
|
10
|
+
export declare function dataFilesDirectoryDelete(argv: string[]): Promise<void>;
|
|
11
|
+
export declare function dataFilesDirectoryMove(argv: string[]): Promise<void>;
|
|
12
|
+
export declare function dataFilesVersions(argv: string[]): Promise<void>;
|
|
13
|
+
export declare function dataFilesCreateVersion(argv: string[]): Promise<void>;
|
|
14
|
+
export declare function dataFilesCopy(argv: string[]): Promise<void>;
|
|
15
|
+
export declare function dataFilesMove(argv: string[]): Promise<void>;
|
|
16
|
+
export declare function dataFilesRename(argv: string[]): Promise<void>;
|
|
17
|
+
export declare function dataFilesAccessList(argv: string[]): Promise<void>;
|
|
18
|
+
export declare function dataFilesAccessGrant(argv: string[]): Promise<void>;
|
|
19
|
+
export declare function dataFilesAccessUpdate(argv: string[]): Promise<void>;
|
|
20
|
+
export declare function dataFilesAccessRevoke(argv: string[]): Promise<void>;
|
|
21
|
+
export declare function dataFilesAccessResolve(argv: string[]): Promise<void>;
|
|
22
|
+
export declare function dataFilesInheritance(argv: string[]): Promise<void>;
|
|
23
|
+
export declare function dataFilesShare(argv: string[]): Promise<void>;
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { booleanFlag, optionalBooleanFlag, optionalIntegerFlag, stringFlag } from "../../../lib/args.js";
|
|
2
|
+
import { blocksRequest } from "../../../lib/api.js";
|
|
3
|
+
import { confirmMutation } from "../../../lib/confirm.js";
|
|
4
|
+
import { compact, jsonBodyFlag, listFlag } from "../../../lib/json-flag.js";
|
|
5
|
+
import { writeOutput } from "../../../lib/output.js";
|
|
6
|
+
import { requestContext } from "../../../lib/request-context.js";
|
|
7
|
+
import { parseCommand, selectedProject } from "../../../lib/workspace.js";
|
|
8
|
+
export async function dataFilesList(argv) {
|
|
9
|
+
const { flags } = parseCommand(argv);
|
|
10
|
+
await read("/data/v4/objects/get-objects", flags, compact({
|
|
11
|
+
cursor: stringFlag(flags, "cursor") || undefined,
|
|
12
|
+
limit: optionalIntegerFlag(flags, "limit"),
|
|
13
|
+
moduleName: optionalIntegerFlag(flags, "module-name"),
|
|
14
|
+
parentDirectoryId: parentId(flags) || undefined,
|
|
15
|
+
search: stringFlag(flags, "search") || undefined,
|
|
16
|
+
type: stringFlag(flags, "type") || undefined
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
export async function dataFilesSearch(argv) {
|
|
20
|
+
const { args, flags } = parseCommand(argv);
|
|
21
|
+
await read("/data/v4/objects/search-objects", flags, compact({
|
|
22
|
+
cursor: stringFlag(flags, "cursor") || undefined,
|
|
23
|
+
directoryId: stringFlag(flags, "directory-id") || undefined,
|
|
24
|
+
limit: optionalIntegerFlag(flags, "limit"),
|
|
25
|
+
query: args[0] || stringFlag(flags, "query", { required: true }),
|
|
26
|
+
type: stringFlag(flags, "type") || undefined
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
export async function dataFilesTrash(argv) {
|
|
30
|
+
const { flags } = parseCommand(argv);
|
|
31
|
+
await read("/data/v4/objects/get-trash", flags, pageQuery(flags));
|
|
32
|
+
}
|
|
33
|
+
export async function dataFilesShared(argv) {
|
|
34
|
+
const { flags } = parseCommand(argv);
|
|
35
|
+
await read("/data/v4/objects/get-shared-objects", flags, pageQuery(flags));
|
|
36
|
+
}
|
|
37
|
+
export async function dataFilesRestore(argv) {
|
|
38
|
+
const { args, flags } = parseCommand(argv);
|
|
39
|
+
const resourceId = resourceArg(args, flags);
|
|
40
|
+
await mutate("/data/v4/objects/restore-from-trash", flags, { resourceId }, `Restore storage object '${resourceId}' from trash.`);
|
|
41
|
+
}
|
|
42
|
+
export async function dataFilesPurge(argv) {
|
|
43
|
+
const { args, flags } = parseCommand(argv);
|
|
44
|
+
const resourceId = resourceArg(args, flags);
|
|
45
|
+
await mutate("/data/v4/objects/delete-from-trash", flags, { resourceId }, `Permanently delete storage object '${resourceId}' from trash.`);
|
|
46
|
+
}
|
|
47
|
+
export async function dataFilesDirectoryCreate(argv) {
|
|
48
|
+
const { args, flags } = parseCommand(argv);
|
|
49
|
+
const base = await jsonBodyFlag(flags);
|
|
50
|
+
const name = args[0] || stringFlag(flags, "name") || String(base.name ?? "");
|
|
51
|
+
if (!name)
|
|
52
|
+
throw new Error("Provide a directory name as the first argument or --name.");
|
|
53
|
+
const body = { ...base, ...compact({
|
|
54
|
+
allowedFileExtensions: listFlag(flags, "allowed-extensions"),
|
|
55
|
+
configurationName: stringFlag(flags, "configuration-name") || undefined,
|
|
56
|
+
description: stringFlag(flags, "description") || undefined,
|
|
57
|
+
moduleName: optionalIntegerFlag(flags, "module-name"),
|
|
58
|
+
name,
|
|
59
|
+
parentDirectoryId: parentId(flags) || undefined
|
|
60
|
+
}) };
|
|
61
|
+
await mutate("/data/v4/directory/create-directory", flags, body, `Create storage directory '${name}'.`);
|
|
62
|
+
}
|
|
63
|
+
export async function dataFilesDirectoryGet(argv) {
|
|
64
|
+
const { args, flags } = parseCommand(argv);
|
|
65
|
+
const directoryId = directoryArg(args, flags);
|
|
66
|
+
await read("/data/v4/directory/get-directory", flags, { directoryId });
|
|
67
|
+
}
|
|
68
|
+
export async function dataFilesDirectoryUpdate(argv) {
|
|
69
|
+
const { args, flags } = parseCommand(argv);
|
|
70
|
+
const directoryId = directoryArg(args, flags);
|
|
71
|
+
const body = { ...(await jsonBodyFlag(flags)), ...compact({
|
|
72
|
+
description: stringFlag(flags, "description") || undefined,
|
|
73
|
+
directoryId,
|
|
74
|
+
name: stringFlag(flags, "name") || undefined
|
|
75
|
+
}) };
|
|
76
|
+
await mutate("/data/v4/directory/update-directory", flags, body, `Update storage directory '${directoryId}'.`);
|
|
77
|
+
}
|
|
78
|
+
export async function dataFilesDirectoryDelete(argv) {
|
|
79
|
+
const { args, flags } = parseCommand(argv);
|
|
80
|
+
const directoryId = directoryArg(args, flags);
|
|
81
|
+
const permanent = booleanFlag(flags, "permanent");
|
|
82
|
+
await mutate("/data/v4/directory/delete-directory", flags, { directoryId, permanent }, `${permanent ? "Permanently delete" : "Move"} storage directory '${directoryId}'${permanent ? "" : " to trash"}.`);
|
|
83
|
+
}
|
|
84
|
+
export async function dataFilesDirectoryMove(argv) {
|
|
85
|
+
const { args, flags } = parseCommand(argv);
|
|
86
|
+
const directoryId = directoryArg(args, flags);
|
|
87
|
+
const targetDirectoryId = stringFlag(flags, "target-directory-id") || stringFlag(flags, "target-id");
|
|
88
|
+
await mutate("/data/v4/directory/move-directory", flags, { directoryId, targetDirectoryId }, `Move storage directory '${directoryId}'.`);
|
|
89
|
+
}
|
|
90
|
+
export async function dataFilesVersions(argv) {
|
|
91
|
+
const { args, flags } = parseCommand(argv);
|
|
92
|
+
await read("/data/v4/files/get-file-versions", flags, compact({
|
|
93
|
+
cursor: stringFlag(flags, "cursor") || undefined,
|
|
94
|
+
fileId: fileArg(args, flags),
|
|
95
|
+
limit: optionalIntegerFlag(flags, "limit")
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
export async function dataFilesCreateVersion(argv) {
|
|
99
|
+
const { args, flags } = parseCommand(argv);
|
|
100
|
+
const fileId = fileArg(args, flags);
|
|
101
|
+
await mutate("/data/v4/files/create-file-version", flags, compact({
|
|
102
|
+
configurationName: stringFlag(flags, "configuration-name") || undefined,
|
|
103
|
+
fileId
|
|
104
|
+
}), `Create a new upload version for file '${fileId}'.`);
|
|
105
|
+
}
|
|
106
|
+
export async function dataFilesCopy(argv) {
|
|
107
|
+
const { args, flags } = parseCommand(argv);
|
|
108
|
+
const fileId = fileArg(args, flags);
|
|
109
|
+
const targetDirectoryId = stringFlag(flags, "target-directory-id", { required: true });
|
|
110
|
+
await mutate("/data/v4/files/copy-file", flags, {
|
|
111
|
+
copyAccessPolicies: booleanFlag(flags, "copy-access-policies"), fileId, targetDirectoryId
|
|
112
|
+
}, `Copy file '${fileId}' to directory '${targetDirectoryId}'.`);
|
|
113
|
+
}
|
|
114
|
+
export async function dataFilesMove(argv) {
|
|
115
|
+
const { args, flags } = parseCommand(argv);
|
|
116
|
+
const fileId = fileArg(args, flags);
|
|
117
|
+
const targetDirectoryId = stringFlag(flags, "target-directory-id", { required: true });
|
|
118
|
+
await mutate("/data/v4/files/move-file", flags, { fileId, targetDirectoryId }, `Move file '${fileId}' to directory '${targetDirectoryId}'.`);
|
|
119
|
+
}
|
|
120
|
+
export async function dataFilesRename(argv) {
|
|
121
|
+
const { args, flags } = parseCommand(argv);
|
|
122
|
+
const fileId = fileArg(args, flags);
|
|
123
|
+
const name = stringFlag(flags, "name", { required: true });
|
|
124
|
+
await mutate("/data/v4/files/rename-file", flags, { fileId, name }, `Rename file '${fileId}' to '${name}'.`);
|
|
125
|
+
}
|
|
126
|
+
export async function dataFilesAccessList(argv) {
|
|
127
|
+
const { args, flags } = parseCommand(argv);
|
|
128
|
+
await read("/data/v4/objects/get-access-policies", flags, { resourceId: resourceArg(args, flags) });
|
|
129
|
+
}
|
|
130
|
+
export async function dataFilesAccessGrant(argv) {
|
|
131
|
+
await accessMutation(argv, "/data/v4/objects/grant-access", "Grant access to");
|
|
132
|
+
}
|
|
133
|
+
export async function dataFilesAccessUpdate(argv) {
|
|
134
|
+
await accessMutation(argv, "/data/v4/objects/update-access-policy", "Update access on", true);
|
|
135
|
+
}
|
|
136
|
+
export async function dataFilesAccessRevoke(argv) {
|
|
137
|
+
const { args, flags } = parseCommand(argv);
|
|
138
|
+
const resourceId = resourceArg(args, flags);
|
|
139
|
+
const policyItemId = stringFlag(flags, "policy-id", { required: true });
|
|
140
|
+
await mutate("/data/v4/objects/revoke-access-policy", flags, { policyItemId, resourceId }, `Revoke access policy '${policyItemId}' from '${resourceId}'.`);
|
|
141
|
+
}
|
|
142
|
+
export async function dataFilesAccessResolve(argv) {
|
|
143
|
+
const { args, flags } = parseCommand(argv);
|
|
144
|
+
await read("/data/v4/objects/resolve-access", flags, { resourceId: resourceArg(args, flags) });
|
|
145
|
+
}
|
|
146
|
+
export async function dataFilesInheritance(argv) {
|
|
147
|
+
const { args, flags } = parseCommand(argv);
|
|
148
|
+
const base = await jsonBodyFlag(flags);
|
|
149
|
+
const value = optionalBooleanFlag(flags, "enabled");
|
|
150
|
+
const inheritsParentAccess = value ?? base.inheritsParentAccess;
|
|
151
|
+
if (typeof inheritsParentAccess !== "boolean")
|
|
152
|
+
throw new Error("Provide --enabled=true|false.");
|
|
153
|
+
const resourceId = resourceArg(args, flags, base);
|
|
154
|
+
await mutate("/data/v4/objects/toggle-inheritance", flags, { ...base, inheritsParentAccess, resourceId }, `Set inheritance on '${resourceId}' to ${inheritsParentAccess}.`);
|
|
155
|
+
}
|
|
156
|
+
export async function dataFilesShare(argv) {
|
|
157
|
+
const { args, flags } = parseCommand(argv);
|
|
158
|
+
const base = await jsonBodyFlag(flags);
|
|
159
|
+
const resourceId = resourceArg(args, flags, base);
|
|
160
|
+
const body = accessBody(base, flags, resourceId);
|
|
161
|
+
delete body.effect;
|
|
162
|
+
delete body.policyItemId;
|
|
163
|
+
await mutate("/data/v4/objects/share-object", flags, body, `Share storage object '${resourceId}'.`);
|
|
164
|
+
}
|
|
165
|
+
async function accessMutation(argv, endpoint, action, update = false) {
|
|
166
|
+
const { args, flags } = parseCommand(argv);
|
|
167
|
+
const base = await jsonBodyFlag(flags);
|
|
168
|
+
const resourceId = resourceArg(args, flags, base);
|
|
169
|
+
const body = accessBody(base, flags, resourceId);
|
|
170
|
+
if (update && !body.policyItemId)
|
|
171
|
+
throw new Error("Provide --policy-id when updating an access policy.");
|
|
172
|
+
await mutate(endpoint, flags, body, `${action} storage object '${resourceId}'.`);
|
|
173
|
+
}
|
|
174
|
+
function accessBody(base, flags, resourceId) {
|
|
175
|
+
const body = { ...base, ...compact({
|
|
176
|
+
effect: stringFlag(flags, "effect") || undefined,
|
|
177
|
+
expiresAt: stringFlag(flags, "expires-at") || undefined,
|
|
178
|
+
permission: stringFlag(flags, "permission") || undefined,
|
|
179
|
+
policyItemId: stringFlag(flags, "policy-id") || undefined,
|
|
180
|
+
principalId: stringFlag(flags, "principal-id") || undefined,
|
|
181
|
+
principalType: stringFlag(flags, "principal-type") || undefined,
|
|
182
|
+
priority: optionalIntegerFlag(flags, "priority"),
|
|
183
|
+
resourceId,
|
|
184
|
+
resourceType: stringFlag(flags, "resource-type") || undefined
|
|
185
|
+
}) };
|
|
186
|
+
for (const field of ["permission", "principalType", "resourceType"]) {
|
|
187
|
+
if (!body[field])
|
|
188
|
+
throw new Error(`Provide --${field.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}.`);
|
|
189
|
+
}
|
|
190
|
+
return body;
|
|
191
|
+
}
|
|
192
|
+
async function read(endpoint, flags, query) {
|
|
193
|
+
const projectKey = await selectedProject(flags);
|
|
194
|
+
const result = await blocksRequest(endpoint, {
|
|
195
|
+
impersonatedProjectAuth: true,
|
|
196
|
+
...requestContext(flags),
|
|
197
|
+
projectTenantId: projectKey,
|
|
198
|
+
query
|
|
199
|
+
});
|
|
200
|
+
writeOutput(result, flags);
|
|
201
|
+
}
|
|
202
|
+
async function mutate(endpoint, flags, body, prompt) {
|
|
203
|
+
if (booleanFlag(flags, "dry-run")) {
|
|
204
|
+
writeOutput({ dryRun: true, endpoint, request: body }, flags);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
await confirmMutation(flags, prompt);
|
|
208
|
+
const projectKey = await selectedProject(flags);
|
|
209
|
+
const result = await blocksRequest(endpoint, {
|
|
210
|
+
body,
|
|
211
|
+
impersonatedProjectAuth: true,
|
|
212
|
+
...requestContext(flags),
|
|
213
|
+
projectTenantId: projectKey
|
|
214
|
+
});
|
|
215
|
+
writeOutput(result, flags);
|
|
216
|
+
}
|
|
217
|
+
function pageQuery(flags) {
|
|
218
|
+
return compact({
|
|
219
|
+
cursor: stringFlag(flags, "cursor") || undefined,
|
|
220
|
+
limit: optionalIntegerFlag(flags, "limit"),
|
|
221
|
+
type: stringFlag(flags, "type") || undefined
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
function parentId(flags) {
|
|
225
|
+
return stringFlag(flags, "parent-directory-id") || stringFlag(flags, "parent-id");
|
|
226
|
+
}
|
|
227
|
+
function resourceArg(args, flags, base = {}) {
|
|
228
|
+
const value = args[0] || stringFlag(flags, "resource-id") || String(base.resourceId ?? "");
|
|
229
|
+
if (!value)
|
|
230
|
+
throw new Error("Provide a resource id as the first argument or --resource-id.");
|
|
231
|
+
return value;
|
|
232
|
+
}
|
|
233
|
+
function directoryArg(args, flags) {
|
|
234
|
+
return args[0] || stringFlag(flags, "directory-id", { required: true });
|
|
235
|
+
}
|
|
236
|
+
function fileArg(args, flags) {
|
|
237
|
+
return args[0] || stringFlag(flags, "file-id", { required: true });
|
|
238
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { optionalIntegerFlag, stringFlag } from "../../../lib/args.js";
|
|
1
|
+
import { booleanFlag, optionalIntegerFlag, stringFlag } from "../../../lib/args.js";
|
|
2
2
|
import { blocksRequest } from "../../../lib/api.js";
|
|
3
|
+
import { confirmMutation } from "../../../lib/confirm.js";
|
|
3
4
|
import { compact, jsonBodyFlag } from "../../../lib/json-flag.js";
|
|
4
5
|
import { writeOutput } from "../../../lib/output.js";
|
|
5
6
|
import { requestContext } from "../../../lib/request-context.js";
|
|
@@ -16,6 +17,7 @@ export async function dataFilesPresignedUploadUrl(argv) {
|
|
|
16
17
|
...compact({
|
|
17
18
|
accessModifier: stringFlag(flags, "access-modifier") || undefined,
|
|
18
19
|
configurationName: stringFlag(flags, "configuration-name") || undefined,
|
|
20
|
+
itemId: stringFlag(flags, "item-id") || undefined,
|
|
19
21
|
metaData: stringFlag(flags, "meta-data") || undefined,
|
|
20
22
|
moduleName: optionalIntegerFlag(flags, "module-name"),
|
|
21
23
|
name: stringFlag(flags, "name", { required: true }),
|
|
@@ -23,8 +25,13 @@ export async function dataFilesPresignedUploadUrl(argv) {
|
|
|
23
25
|
tags: stringFlag(flags, "tags") || undefined
|
|
24
26
|
})
|
|
25
27
|
};
|
|
28
|
+
if (booleanFlag(flags, "dry-run")) {
|
|
29
|
+
writeOutput({ dryRun: true, endpoint: "/data/v4/files/get-pre-signed-url-for-upload", request: body }, flags);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
await confirmMutation(flags, `Create file metadata and an upload URL for '${body.name}'.`);
|
|
26
33
|
const projectKey = await selectedProject(flags);
|
|
27
|
-
const result = await blocksRequest("/data/v4/
|
|
34
|
+
const result = await blocksRequest("/data/v4/files/get-pre-signed-url-for-upload", {
|
|
28
35
|
body,
|
|
29
36
|
impersonatedProjectAuth: true,
|
|
30
37
|
...requestContext(flags),
|
|
@@ -11,12 +11,12 @@ export async function dataFilesUpdateAdditionalInfo(argv) {
|
|
|
11
11
|
const additionalProperties = JSON.parse(additionalPropertiesRaw);
|
|
12
12
|
const body = { additionalProperties, itemId };
|
|
13
13
|
if (booleanFlag(flags, "dry-run")) {
|
|
14
|
-
writeOutput({ dryRun: true, endpoint: "/data/v4/
|
|
14
|
+
writeOutput({ dryRun: true, endpoint: "/data/v4/files/update-file-additional-info", request: body }, flags);
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
17
|
await confirmMutation(flags, `Update additional info for file '${itemId}'.`);
|
|
18
18
|
const projectKey = await selectedProject(flags);
|
|
19
|
-
const result = await blocksRequest("/data/v4/
|
|
19
|
+
const result = await blocksRequest("/data/v4/files/update-file-additional-info", {
|
|
20
20
|
body,
|
|
21
21
|
impersonatedProjectAuth: true,
|
|
22
22
|
...requestContext(flags),
|