@raster-app/cli 0.1.0 → 0.2.0
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/README.md +86 -22
- package/dist/index.js +140 -96
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,10 +8,10 @@ Command-line client for the [Raster](https://raster.app) API. Browse, search, up
|
|
|
8
8
|
npm install -g @raster-app/cli
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Run
|
|
11
|
+
Run a single command without installing — the binary is `raster`:
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
|
-
npx @raster-app/cli whoami
|
|
14
|
+
npx -p @raster-app/cli raster whoami
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
A standalone macOS (Apple Silicon) binary ships with each [GitHub release](https://github.com/raster-app/raster-cli/releases) — no Node required.
|
|
@@ -24,38 +24,102 @@ The CLI uses your organization's API key (create one in Raster under Settings
|
|
|
24
24
|
raster auth login
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
The command validates the key against the API and stores it in `~/.config/raster/config.json` with owner-only permissions. In CI, set `RASTER_API_KEY` instead.
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
The key resolves from the `--api-key` flag, then `RASTER_API_KEY`, then the config file. `raster auth status` shows which source is active.
|
|
30
|
+
|
|
31
|
+
## Org and library are derived from the key
|
|
32
|
+
|
|
33
|
+
An API key is scoped to one organization and a set of libraries. `raster auth login` captures that scope into the config file, so commands resolve it locally — no extra request per command:
|
|
34
|
+
|
|
35
|
+
- **`--org` is optional** — the organization comes from the key.
|
|
36
|
+
- **`--library` is optional when the key has a single library.** When the key can reach several, commands that act on one library ask you to pass `--library <id>` and list the choices.
|
|
37
|
+
|
|
38
|
+
Pass `--org` / `--library` to override, or to pick a library when the key spans more than one. A key supplied via `RASTER_API_KEY` with no prior login resolves its scope from the API on first use. If a key's library access changes in Raster, re-run `raster auth login` to refresh the cached list, or pass `--library`.
|
|
39
|
+
|
|
40
|
+
## Global flags
|
|
41
|
+
|
|
42
|
+
These work on every command, before or after the subcommand.
|
|
43
|
+
|
|
44
|
+
| Flag | Purpose |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| `--api-key <key>` | API key (overrides `RASTER_API_KEY` and the config file) |
|
|
47
|
+
| `--org <organizationId>` | Organization id (derived from the key when omitted) |
|
|
48
|
+
| `--library <libraryId>` | Library id (derived from the key when it has one library) |
|
|
49
|
+
| `--json` | Print the raw API payload to stdout and nothing else |
|
|
50
|
+
| `--verbose` | Log each request to stderr (method, path, masked key, status, duration) |
|
|
30
51
|
|
|
31
52
|
## Commands
|
|
32
53
|
|
|
33
|
-
|
|
34
|
-
|
|
54
|
+
### `auth`
|
|
55
|
+
|
|
56
|
+
| Command | Description |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| `raster auth login` | Validate an API key and store it. Pass `--api-key <key>`, or run interactively to be prompted. |
|
|
59
|
+
| `raster auth logout` | Remove the stored API key. |
|
|
60
|
+
| `raster auth status` | Show which key is in use, its source, and the organization it reaches. |
|
|
61
|
+
|
|
62
|
+
### `whoami`
|
|
63
|
+
|
|
64
|
+
```sh
|
|
35
65
|
raster whoami
|
|
36
|
-
raster libraries ls|create|rename
|
|
37
|
-
raster assets ls|get|search|download|upload|rm|describe|transfer
|
|
38
|
-
raster tags ls|add|rm
|
|
39
|
-
raster orgs create
|
|
40
66
|
```
|
|
41
67
|
|
|
42
|
-
|
|
68
|
+
Show the organization, plan, and libraries the API key can access.
|
|
69
|
+
|
|
70
|
+
### `libraries`
|
|
71
|
+
|
|
72
|
+
| Command | Description | Flags |
|
|
73
|
+
| --- | --- | --- |
|
|
74
|
+
| `raster libraries ls` | List libraries in the organization. | `--page <n>`, `--page-size <n>` |
|
|
75
|
+
| `raster libraries create` | Create a library. | `--name <name>` (required), `--slug <slug>` |
|
|
76
|
+
| `raster libraries rename` | Rename the library (`--library`, or the key's only one). | `--name <name>` (required) |
|
|
77
|
+
|
|
78
|
+
### `assets`
|
|
79
|
+
|
|
80
|
+
Asset ids are always positional. `--library` selects the library when the key has more than one.
|
|
81
|
+
|
|
82
|
+
| Command | Description | Flags |
|
|
83
|
+
| --- | --- | --- |
|
|
84
|
+
| `raster assets ls` | List assets in the library. | `--page <n>`, `--page-size <n>`, `--tag <tag...>` (repeatable, up to 5) |
|
|
85
|
+
| `raster assets get <assetId>` | Show one asset's metadata. | — |
|
|
86
|
+
| `raster assets search <query>` | Search assets across the organization (`--library` scopes to one). | `--page <n>`, `--page-size <n>` |
|
|
87
|
+
| `raster assets download <assetId>` | Download the asset's file to disk. | `-o, --output <path>`, `--force` |
|
|
88
|
+
| `raster assets upload <files...>` | Upload local files (batched at 20 per request). | — |
|
|
89
|
+
| `raster assets rm <assetIds...>` | Move assets to trash (recoverable). | `--yes` (skip the confirm prompt) |
|
|
90
|
+
| `raster assets describe <assetId>` | Set an asset's description. | `--text <description>` (required) |
|
|
91
|
+
| `raster assets transfer <assetIds...>` | Move assets to another library. | `--to <libraryId>` (required) |
|
|
92
|
+
|
|
93
|
+
### `tags`
|
|
94
|
+
|
|
95
|
+
| Command | Description | Flags |
|
|
96
|
+
| --- | --- | --- |
|
|
97
|
+
| `raster tags ls` | List tags in the library. | `--limit <n>` |
|
|
98
|
+
| `raster tags add <assetIds...>` | Add tags to assets. | `--tag <tag...>` (required, repeatable) |
|
|
99
|
+
| `raster tags rm <assetIds...>` | Remove tags from assets. | `--tag <tag...>` (required, repeatable) |
|
|
100
|
+
|
|
101
|
+
### `orgs`
|
|
43
102
|
|
|
44
103
|
```sh
|
|
45
|
-
raster
|
|
46
|
-
raster assets ls --org org_123 --library lib_456 --tag sunset
|
|
47
|
-
raster assets upload --org org_123 --library lib_456 ./photos/*.png
|
|
48
|
-
raster assets search --org org_123 "golden hour" --json | jq '.hits[].id'
|
|
49
|
-
raster orgs create --email you@example.com --save
|
|
104
|
+
raster orgs create --email <email> [--name <name>] [--save]
|
|
50
105
|
```
|
|
51
106
|
|
|
52
|
-
|
|
107
|
+
Create a library with no account (held 30 days until claimed). Prints the claim URL; `--save` stores the minted key. Anonymous — sends no API key.
|
|
108
|
+
|
|
109
|
+
## Examples
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
raster libraries ls
|
|
113
|
+
raster assets ls --library brand --tag sunset
|
|
114
|
+
raster assets upload --library brand ./photos/*.png
|
|
115
|
+
raster assets search "golden hour" --json | jq '.hits[].id'
|
|
116
|
+
raster tags add asset_123 asset_456 --tag launch --library brand
|
|
117
|
+
raster assets transfer asset_123 --to archive --library brand
|
|
118
|
+
```
|
|
53
119
|
|
|
54
|
-
## Output
|
|
120
|
+
## Output and scripting
|
|
55
121
|
|
|
56
|
-
|
|
57
|
-
- `--json` prints the raw API payload to stdout and nothing else.
|
|
58
|
-
- `--verbose` logs each request (method, path, masked key, status, duration) to stderr.
|
|
122
|
+
Human-readable tables print to stdout; progress and notes go to stderr, so stdout stays pipeable. `--json` prints only the raw API payload to stdout. `--verbose` logs each request to stderr with the key masked.
|
|
59
123
|
|
|
60
124
|
## Exit codes
|
|
61
125
|
|
|
@@ -88,7 +152,7 @@ bun run gen:types # regenerate src/api/openapi.d.ts from the live OpenAPI docu
|
|
|
88
152
|
bun run build # bundle dist/index.js
|
|
89
153
|
```
|
|
90
154
|
|
|
91
|
-
Types are generated from the public OpenAPI document at `https://api.raster.app/openapi.json`; CI fails when the committed types drift from production. The published package bundles its three libraries (`commander`, `zod`, `openapi-fetch`) into `dist/index.js` — installing the CLI pulls zero dependencies.
|
|
155
|
+
Types are generated from the public OpenAPI document at `https://api.raster.app/openapi.json`; CI fails when the committed types drift from production. The published package bundles its three libraries (`commander`, `zod`, `openapi-fetch`) into `dist/index.js` — installing the CLI pulls zero dependencies.
|
|
92
156
|
|
|
93
157
|
## License
|
|
94
158
|
|
package/dist/index.js
CHANGED
|
@@ -16337,7 +16337,7 @@ config(en_default());
|
|
|
16337
16337
|
// package.json
|
|
16338
16338
|
var package_default = {
|
|
16339
16339
|
name: "@raster-app/cli",
|
|
16340
|
-
version: "0.
|
|
16340
|
+
version: "0.2.0",
|
|
16341
16341
|
description: "Command-line client for the Raster API",
|
|
16342
16342
|
license: "Apache-2.0",
|
|
16343
16343
|
type: "module",
|
|
@@ -17032,7 +17032,9 @@ var CONFIG_FILE_NAME = "config.json";
|
|
|
17032
17032
|
var CONFIG_FILE_MODE = 384;
|
|
17033
17033
|
var CONFIG_DIR_MODE = 448;
|
|
17034
17034
|
var configSchema = exports_external.object({
|
|
17035
|
-
apiKey: exports_external.string().min(1).optional()
|
|
17035
|
+
apiKey: exports_external.string().min(1).optional(),
|
|
17036
|
+
organizationId: exports_external.string().min(1).optional(),
|
|
17037
|
+
libraries: exports_external.array(exports_external.string()).optional()
|
|
17036
17038
|
});
|
|
17037
17039
|
function configDir(env) {
|
|
17038
17040
|
if (env.RASTER_CONFIG_HOME)
|
|
@@ -17204,6 +17206,22 @@ async function createCommandContext(globals, overrides = {}) {
|
|
|
17204
17206
|
const baseUrl = validateBaseUrl(env.RASTER_API_BASE_URL ?? DEFAULT_BASE_URL);
|
|
17205
17207
|
const baseFetch = overrides.fetch ?? globalThis.fetch;
|
|
17206
17208
|
const instrumentedFetch = instrumentFetch(baseFetch, output, apiKey ? maskApiKey(apiKey.key) : null);
|
|
17209
|
+
const clientFactory = (clientOverrides) => createApiClient({
|
|
17210
|
+
baseUrl,
|
|
17211
|
+
apiKey: clientOverrides ? clientOverrides.apiKey : apiKey?.key ?? null,
|
|
17212
|
+
fetch: instrumentedFetch
|
|
17213
|
+
});
|
|
17214
|
+
let viewerPromise = null;
|
|
17215
|
+
const loadViewer = () => {
|
|
17216
|
+
if (!viewerPromise) {
|
|
17217
|
+
if (!apiKey) {
|
|
17218
|
+
throw new AuthSetupError("No API key found. Run `raster auth login` or set RASTER_API_KEY.");
|
|
17219
|
+
}
|
|
17220
|
+
viewerPromise = unwrapResult(() => clientFactory({ apiKey: apiKey.key }).GET("/me", { params: { header: VERSION_HEADER } }));
|
|
17221
|
+
}
|
|
17222
|
+
return viewerPromise;
|
|
17223
|
+
};
|
|
17224
|
+
const cacheMatchesKey = config2.apiKey !== undefined && apiKey?.key === config2.apiKey;
|
|
17207
17225
|
return {
|
|
17208
17226
|
...output,
|
|
17209
17227
|
env,
|
|
@@ -17211,13 +17229,35 @@ async function createCommandContext(globals, overrides = {}) {
|
|
|
17211
17229
|
isInteractive: overrides.isInteractive ?? process.stdin.isTTY === true,
|
|
17212
17230
|
apiKey,
|
|
17213
17231
|
fetch: instrumentedFetch,
|
|
17214
|
-
clientFactory
|
|
17215
|
-
baseUrl,
|
|
17216
|
-
apiKey: clientOverrides ? clientOverrides.apiKey : apiKey?.key ?? null,
|
|
17217
|
-
fetch: instrumentedFetch
|
|
17218
|
-
}),
|
|
17232
|
+
clientFactory,
|
|
17219
17233
|
confirm: overrides.confirm ?? promptConfirm,
|
|
17220
|
-
promptSecret: overrides.promptSecret ?? promptSecret
|
|
17234
|
+
promptSecret: overrides.promptSecret ?? promptSecret,
|
|
17235
|
+
explicitLibrary: globals.library,
|
|
17236
|
+
resolveOrg: async () => {
|
|
17237
|
+
if (globals.org)
|
|
17238
|
+
return globals.org;
|
|
17239
|
+
if (cacheMatchesKey && config2.organizationId)
|
|
17240
|
+
return config2.organizationId;
|
|
17241
|
+
const viewer = await loadViewer();
|
|
17242
|
+
if (!viewer.organizationId) {
|
|
17243
|
+
throw new CliError("Could not determine the organization from the API key.", EXIT_CODES.generic);
|
|
17244
|
+
}
|
|
17245
|
+
return viewer.organizationId;
|
|
17246
|
+
},
|
|
17247
|
+
resolveLibrary: async () => {
|
|
17248
|
+
if (globals.library)
|
|
17249
|
+
return globals.library;
|
|
17250
|
+
const cachedLibraries = cacheMatchesKey ? config2.libraries : undefined;
|
|
17251
|
+
const source = cachedLibraries ?? (await loadViewer()).libraries ?? [];
|
|
17252
|
+
const libraries = source.filter((value) => typeof value === "string");
|
|
17253
|
+
const onlyLibrary = libraries[0];
|
|
17254
|
+
if (libraries.length === 1 && onlyLibrary)
|
|
17255
|
+
return onlyLibrary;
|
|
17256
|
+
if (libraries.length === 0) {
|
|
17257
|
+
throw new AuthSetupError("The API key has no library access.");
|
|
17258
|
+
}
|
|
17259
|
+
throw new UsageError(`The API key can access ${libraries.length} libraries (${libraries.join(", ")}). Pass --library <id>.`);
|
|
17260
|
+
}
|
|
17221
17261
|
};
|
|
17222
17262
|
}
|
|
17223
17263
|
function instrumentFetch(baseFetch, output, maskedKey) {
|
|
@@ -17284,11 +17324,7 @@ var SEARCH_HIT_COLUMNS = [
|
|
|
17284
17324
|
{ header: "NAME", value: (hit) => hit.name ?? "" },
|
|
17285
17325
|
{ header: "LIBRARY", value: (hit) => hit.libraryId ?? "" }
|
|
17286
17326
|
];
|
|
17287
|
-
var
|
|
17288
|
-
org: exports_external.string().min(1),
|
|
17289
|
-
library: exports_external.string().min(1)
|
|
17290
|
-
});
|
|
17291
|
-
var listOptionsSchema = inLibraryOptionsSchema.extend({
|
|
17327
|
+
var listOptionsSchema = exports_external.object({
|
|
17292
17328
|
page: exports_external.coerce.number().int().min(1).optional(),
|
|
17293
17329
|
pageSize: exports_external.coerce.number().int().min(1).optional(),
|
|
17294
17330
|
tag: exports_external.array(exports_external.string().min(1)).default([])
|
|
@@ -17298,10 +17334,12 @@ async function listAssetsCommand(context, options) {
|
|
|
17298
17334
|
throw new ValidationError(`At most ${MAX_TAGS_PER_QUERY} --tag filters are supported per query.`);
|
|
17299
17335
|
}
|
|
17300
17336
|
requireApiKey(context);
|
|
17337
|
+
const organizationId = await context.resolveOrg();
|
|
17338
|
+
const libraryId = await context.resolveLibrary();
|
|
17301
17339
|
const client = context.clientFactory();
|
|
17302
17340
|
const assets = await unwrapResult(() => client.GET("/organizations/{organizationId}/libraries/{libraryId}/assets", {
|
|
17303
17341
|
params: {
|
|
17304
|
-
path: { organizationId
|
|
17342
|
+
path: { organizationId, libraryId },
|
|
17305
17343
|
header: VERSION_HEADER,
|
|
17306
17344
|
query: {
|
|
17307
17345
|
page: options.page,
|
|
@@ -17316,10 +17354,9 @@ async function listAssetsCommand(context, options) {
|
|
|
17316
17354
|
}
|
|
17317
17355
|
renderTable(context, assets, ASSET_COLUMNS);
|
|
17318
17356
|
}
|
|
17319
|
-
|
|
17320
|
-
async function getAssetCommand(context, assetId, options) {
|
|
17357
|
+
async function getAssetCommand(context, assetId) {
|
|
17321
17358
|
requireApiKey(context);
|
|
17322
|
-
const asset = await fetchAsset(context,
|
|
17359
|
+
const asset = await fetchAsset(context, assetId);
|
|
17323
17360
|
if (context.json) {
|
|
17324
17361
|
printJson(context, asset);
|
|
17325
17362
|
return;
|
|
@@ -17335,28 +17372,29 @@ async function getAssetCommand(context, assetId, options) {
|
|
|
17335
17372
|
{ label: "url", value: asset.url ?? "" }
|
|
17336
17373
|
]);
|
|
17337
17374
|
}
|
|
17338
|
-
async function fetchAsset(context,
|
|
17375
|
+
async function fetchAsset(context, assetId) {
|
|
17376
|
+
const organizationId = await context.resolveOrg();
|
|
17377
|
+
const libraryId = await context.resolveLibrary();
|
|
17339
17378
|
const client = context.clientFactory();
|
|
17340
17379
|
return unwrapResult(() => client.GET("/organizations/{organizationId}/libraries/{libraryId}/assets/{assetId}", {
|
|
17341
17380
|
params: { path: { organizationId, libraryId, assetId }, header: VERSION_HEADER }
|
|
17342
17381
|
}));
|
|
17343
17382
|
}
|
|
17344
17383
|
var searchOptionsSchema = exports_external.object({
|
|
17345
|
-
org: exports_external.string().min(1),
|
|
17346
|
-
library: exports_external.array(exports_external.string().min(1)).default([]),
|
|
17347
17384
|
page: exports_external.coerce.number().int().min(1).optional(),
|
|
17348
17385
|
pageSize: exports_external.coerce.number().int().min(1).optional()
|
|
17349
17386
|
});
|
|
17350
17387
|
async function searchAssetsCommand(context, query, options) {
|
|
17351
17388
|
requireApiKey(context);
|
|
17389
|
+
const organizationId = await context.resolveOrg();
|
|
17352
17390
|
const client = context.clientFactory();
|
|
17353
17391
|
const result = await unwrapResult(() => client.GET("/organizations/{organizationId}/search/assets", {
|
|
17354
17392
|
params: {
|
|
17355
|
-
path: { organizationId
|
|
17393
|
+
path: { organizationId },
|
|
17356
17394
|
header: VERSION_HEADER,
|
|
17357
17395
|
query: {
|
|
17358
17396
|
q: query,
|
|
17359
|
-
libraries:
|
|
17397
|
+
libraries: context.explicitLibrary,
|
|
17360
17398
|
page: options.page,
|
|
17361
17399
|
pageSize: options.pageSize
|
|
17362
17400
|
}
|
|
@@ -17369,13 +17407,13 @@ async function searchAssetsCommand(context, query, options) {
|
|
|
17369
17407
|
note(context, `${result.found} result(s), page ${result.page}.`);
|
|
17370
17408
|
renderTable(context, result.hits, SEARCH_HIT_COLUMNS);
|
|
17371
17409
|
}
|
|
17372
|
-
var downloadOptionsSchema =
|
|
17410
|
+
var downloadOptionsSchema = exports_external.object({
|
|
17373
17411
|
output: exports_external.string().min(1).optional(),
|
|
17374
17412
|
force: exports_external.boolean().default(false)
|
|
17375
17413
|
});
|
|
17376
17414
|
async function downloadAssetCommand(context, assetId, options) {
|
|
17377
17415
|
requireApiKey(context);
|
|
17378
|
-
const asset = await fetchAsset(context,
|
|
17416
|
+
const asset = await fetchAsset(context, assetId);
|
|
17379
17417
|
const fileUrl = asset.url;
|
|
17380
17418
|
if (!fileUrl)
|
|
17381
17419
|
throw new CliError("Asset has no file URL to download.", EXIT_CODES.generic);
|
|
@@ -17399,11 +17437,12 @@ async function downloadAssetCommand(context, assetId, options) {
|
|
|
17399
17437
|
var uploadedAssetsSchema = exports_external.object({
|
|
17400
17438
|
assets: exports_external.array(exports_external.looseObject({ id: exports_external.string().optional(), name: exports_external.string().nullish() }))
|
|
17401
17439
|
});
|
|
17402
|
-
|
|
17403
|
-
async function uploadAssetsCommand(context, files, options) {
|
|
17440
|
+
async function uploadAssetsCommand(context, files) {
|
|
17404
17441
|
if (files.length === 0)
|
|
17405
17442
|
throw new UsageError("Provide at least one file to upload.");
|
|
17406
17443
|
const { key } = requireApiKey(context);
|
|
17444
|
+
const organizationId = await context.resolveOrg();
|
|
17445
|
+
const libraryId = await context.resolveLibrary();
|
|
17407
17446
|
const batches = chunk(files, MAX_UPLOAD_FILES);
|
|
17408
17447
|
const uploadedNames = [];
|
|
17409
17448
|
const payloads = [];
|
|
@@ -17421,7 +17460,7 @@ async function uploadAssetsCommand(context, files, options) {
|
|
|
17421
17460
|
if (batches.length > 1) {
|
|
17422
17461
|
note(context, `Uploading batch ${batchIndex + 1}/${batches.length} (${batch.length} files)…`);
|
|
17423
17462
|
}
|
|
17424
|
-
const response = await context.fetch(`${context.baseUrl}/organizations/${
|
|
17463
|
+
const response = await context.fetch(`${context.baseUrl}/organizations/${organizationId}/libraries/${libraryId}/assets`, { method: "POST", headers: buildRequestHeaders(key), body: formData });
|
|
17425
17464
|
const payload = await parseEnvelope(response);
|
|
17426
17465
|
payloads.push(payload);
|
|
17427
17466
|
const parsed = uploadedAssetsSchema.safeParse(payload);
|
|
@@ -17439,7 +17478,7 @@ async function uploadAssetsCommand(context, files, options) {
|
|
|
17439
17478
|
`);
|
|
17440
17479
|
}
|
|
17441
17480
|
}
|
|
17442
|
-
var removeOptionsSchema =
|
|
17481
|
+
var removeOptionsSchema = exports_external.object({
|
|
17443
17482
|
yes: exports_external.boolean().default(false)
|
|
17444
17483
|
});
|
|
17445
17484
|
async function removeAssetsCommand(context, assetIds, options) {
|
|
@@ -17449,6 +17488,8 @@ async function removeAssetsCommand(context, assetIds, options) {
|
|
|
17449
17488
|
throw new ValidationError(`At most ${MAX_DELETE_IDS} asset ids are supported per call.`);
|
|
17450
17489
|
}
|
|
17451
17490
|
requireApiKey(context);
|
|
17491
|
+
const organizationId = await context.resolveOrg();
|
|
17492
|
+
const libraryId = await context.resolveLibrary();
|
|
17452
17493
|
if (!options.yes && context.isInteractive) {
|
|
17453
17494
|
const confirmed = await context.confirm(`Move ${assetIds.length} asset(s) to trash?`);
|
|
17454
17495
|
if (!confirmed) {
|
|
@@ -17458,10 +17499,7 @@ async function removeAssetsCommand(context, assetIds, options) {
|
|
|
17458
17499
|
}
|
|
17459
17500
|
const client = context.clientFactory();
|
|
17460
17501
|
const result = await unwrapResult(() => client.DELETE("/organizations/{organizationId}/libraries/{libraryId}/assets", {
|
|
17461
|
-
params: {
|
|
17462
|
-
path: { organizationId: options.org, libraryId: options.library },
|
|
17463
|
-
header: VERSION_HEADER
|
|
17464
|
-
},
|
|
17502
|
+
params: { path: { organizationId, libraryId }, header: VERSION_HEADER },
|
|
17465
17503
|
body: { ids: assetIds }
|
|
17466
17504
|
}));
|
|
17467
17505
|
if (context.json) {
|
|
@@ -17470,15 +17508,17 @@ async function removeAssetsCommand(context, assetIds, options) {
|
|
|
17470
17508
|
}
|
|
17471
17509
|
note(context, `Moved ${assetIds.length} asset(s) to trash. They are recoverable from the library trash.`);
|
|
17472
17510
|
}
|
|
17473
|
-
var describeOptionsSchema =
|
|
17511
|
+
var describeOptionsSchema = exports_external.object({
|
|
17474
17512
|
text: exports_external.string().min(1)
|
|
17475
17513
|
});
|
|
17476
17514
|
async function describeAssetCommand(context, assetId, options) {
|
|
17477
17515
|
requireApiKey(context);
|
|
17516
|
+
const organizationId = await context.resolveOrg();
|
|
17517
|
+
const libraryId = await context.resolveLibrary();
|
|
17478
17518
|
const client = context.clientFactory();
|
|
17479
17519
|
const asset = await unwrapResult(() => client.PATCH("/organizations/{organizationId}/libraries/{libraryId}/assets/{assetId}/description", {
|
|
17480
17520
|
params: {
|
|
17481
|
-
path: { organizationId
|
|
17521
|
+
path: { organizationId, libraryId, assetId },
|
|
17482
17522
|
header: VERSION_HEADER
|
|
17483
17523
|
},
|
|
17484
17524
|
body: { description: options.text }
|
|
@@ -17489,36 +17529,36 @@ async function describeAssetCommand(context, assetId, options) {
|
|
|
17489
17529
|
}
|
|
17490
17530
|
note(context, "Description updated.");
|
|
17491
17531
|
}
|
|
17492
|
-
var transferOptionsSchema =
|
|
17493
|
-
to: exports_external.string().min(1)
|
|
17494
|
-
asset: exports_external.array(exports_external.string().min(1)).min(1)
|
|
17532
|
+
var transferOptionsSchema = exports_external.object({
|
|
17533
|
+
to: exports_external.string().min(1)
|
|
17495
17534
|
});
|
|
17496
|
-
async function transferAssetsCommand(context, options) {
|
|
17535
|
+
async function transferAssetsCommand(context, assetIds, options) {
|
|
17536
|
+
if (assetIds.length === 0)
|
|
17537
|
+
throw new UsageError("Provide at least one asset id.");
|
|
17497
17538
|
requireApiKey(context);
|
|
17539
|
+
const organizationId = await context.resolveOrg();
|
|
17540
|
+
const libraryId = await context.resolveLibrary();
|
|
17498
17541
|
const client = context.clientFactory();
|
|
17499
17542
|
const result = await unwrapResult(() => client.POST("/organizations/{organizationId}/libraries/{libraryId}/assets/transfer", {
|
|
17500
|
-
params: {
|
|
17501
|
-
|
|
17502
|
-
header: VERSION_HEADER
|
|
17503
|
-
},
|
|
17504
|
-
body: { targetLibraryId: options.to, assetIds: options.asset }
|
|
17543
|
+
params: { path: { organizationId, libraryId }, header: VERSION_HEADER },
|
|
17544
|
+
body: { targetLibraryId: options.to, assetIds }
|
|
17505
17545
|
}));
|
|
17506
17546
|
if (context.json) {
|
|
17507
17547
|
printJson(context, result);
|
|
17508
17548
|
return;
|
|
17509
17549
|
}
|
|
17510
|
-
note(context, `Transferred ${
|
|
17550
|
+
note(context, `Transferred ${assetIds.length} asset(s) to library ${options.to}.`);
|
|
17511
17551
|
}
|
|
17512
17552
|
function registerAssetCommands(program2, runAction) {
|
|
17513
17553
|
const assets = program2.command("assets").description("Work with assets in a library");
|
|
17514
|
-
assets.command("ls").description("List assets in
|
|
17515
|
-
assets.command("get").description("Show a single asset").argument("<assetId>", "Asset id").
|
|
17516
|
-
assets.command("search").description("Search assets across the organization
|
|
17517
|
-
assets.command("download").description("Download an asset's file").argument("<assetId>", "Asset id").
|
|
17518
|
-
assets.command("upload").description("Upload local files as assets").argument("<files...>", "Local file paths").
|
|
17519
|
-
assets.command("rm").description("Move assets to trash (recoverable)").argument("<assetIds...>", "Asset ids").
|
|
17520
|
-
assets.command("describe").description("Set an asset's description").argument("<assetId>", "Asset id").requiredOption("--
|
|
17521
|
-
assets.command("transfer").description("Move assets to another library").
|
|
17554
|
+
assets.command("ls").description("List assets in the library").option("--page <number>", "Page number (1-based)").option("--page-size <number>", "Results per page").option("--tag <tag...>", "Filter by tag (repeatable, up to 5)").action((options, command) => runAction(command, (context) => listAssetsCommand(context, parseOptions(listOptionsSchema, options))));
|
|
17555
|
+
assets.command("get").description("Show a single asset").argument("<assetId>", "Asset id").action((assetId, _options, command) => runAction(command, (context) => getAssetCommand(context, assetId)));
|
|
17556
|
+
assets.command("search").description("Search assets across the organization (pass --library to scope to one)").argument("<query>", "Search query").option("--page <number>", "Page number (1-based)").option("--page-size <number>", "Results per page").action((query, options, command) => runAction(command, (context) => searchAssetsCommand(context, query, parseOptions(searchOptionsSchema, options))));
|
|
17557
|
+
assets.command("download").description("Download an asset's file").argument("<assetId>", "Asset id").option("-o, --output <path>", "Target file path").option("--force", "Overwrite the target file if it exists").action((assetId, options, command) => runAction(command, (context) => downloadAssetCommand(context, assetId, parseOptions(downloadOptionsSchema, options))));
|
|
17558
|
+
assets.command("upload").description("Upload local files as assets").argument("<files...>", "Local file paths").action((files, _options, command) => runAction(command, (context) => uploadAssetsCommand(context, files)));
|
|
17559
|
+
assets.command("rm").description("Move assets to trash (recoverable)").argument("<assetIds...>", "Asset ids").option("--yes", "Skip the confirmation prompt").action((assetIds, options, command) => runAction(command, (context) => removeAssetsCommand(context, assetIds, parseOptions(removeOptionsSchema, options))));
|
|
17560
|
+
assets.command("describe").description("Set an asset's description").argument("<assetId>", "Asset id").requiredOption("--text <description>", "Description text").action((assetId, options, command) => runAction(command, (context) => describeAssetCommand(context, assetId, parseOptions(describeOptionsSchema, options))));
|
|
17561
|
+
assets.command("transfer").description("Move assets to another library").argument("<assetIds...>", "Asset ids to move").requiredOption("--to <libraryId>", "Target library id").action((assetIds, options, command) => runAction(command, (context) => transferAssetsCommand(context, assetIds, parseOptions(transferOptionsSchema, options))));
|
|
17522
17562
|
}
|
|
17523
17563
|
|
|
17524
17564
|
// src/commands/auth.ts
|
|
@@ -17526,23 +17566,26 @@ async function fetchViewer(context, apiKey) {
|
|
|
17526
17566
|
const client = context.clientFactory({ apiKey });
|
|
17527
17567
|
return unwrapResult(() => client.GET("/me", { params: { header: VERSION_HEADER } }));
|
|
17528
17568
|
}
|
|
17529
|
-
|
|
17530
|
-
apiKey
|
|
17531
|
-
|
|
17532
|
-
|
|
17533
|
-
const promptedKey = options.apiKey ?? (context.isInteractive ? await context.promptSecret("Paste your Raster API key") : null);
|
|
17534
|
-
if (!promptedKey) {
|
|
17569
|
+
async function loginCommand(context) {
|
|
17570
|
+
const flagKey = context.apiKey?.source === "flag" ? context.apiKey.key : null;
|
|
17571
|
+
const key = flagKey ?? (context.isInteractive ? await context.promptSecret("Paste your Raster API key") : null);
|
|
17572
|
+
if (!key) {
|
|
17535
17573
|
throw new UsageError("Provide a key with --api-key, or run `raster auth login` in an interactive terminal.");
|
|
17536
17574
|
}
|
|
17537
|
-
const viewer = await fetchViewer(context,
|
|
17575
|
+
const viewer = await fetchViewer(context, key);
|
|
17538
17576
|
const config2 = await readConfig(context.env);
|
|
17539
|
-
await writeConfig({
|
|
17577
|
+
await writeConfig({
|
|
17578
|
+
...config2,
|
|
17579
|
+
apiKey: key,
|
|
17580
|
+
organizationId: viewer?.organizationId,
|
|
17581
|
+
libraries: (viewer?.libraries ?? []).filter((library) => typeof library === "string")
|
|
17582
|
+
}, context.env);
|
|
17540
17583
|
if (context.json) {
|
|
17541
17584
|
printJson(context, viewer);
|
|
17542
17585
|
return;
|
|
17543
17586
|
}
|
|
17544
17587
|
const organizationLabel = viewer?.organizationName ?? viewer?.organizationId ?? "your organization";
|
|
17545
|
-
note(context, `Logged in to ${organizationLabel} as ${maskApiKey(
|
|
17588
|
+
note(context, `Logged in to ${organizationLabel} as ${maskApiKey(key)}. Key stored in ${configPath(context.env)}.`);
|
|
17546
17589
|
}
|
|
17547
17590
|
async function logoutCommand(context) {
|
|
17548
17591
|
const config2 = await readConfig(context.env);
|
|
@@ -17599,7 +17642,7 @@ async function whoamiCommand(context) {
|
|
|
17599
17642
|
}
|
|
17600
17643
|
function registerAuthCommands(program2, runAction) {
|
|
17601
17644
|
const auth = program2.command("auth").description("Manage CLI authentication");
|
|
17602
|
-
auth.command("login").description("Validate an API key against the API and store it
|
|
17645
|
+
auth.command("login").description("Validate an API key against the API and store it (pass --api-key, or run interactively to be prompted)").action((_options, command) => runAction(command, (context) => loginCommand(context)));
|
|
17603
17646
|
auth.command("logout").description("Remove the stored API key").action((_options, command) => runAction(command, (context) => logoutCommand(context)));
|
|
17604
17647
|
auth.command("status").description("Show which API key is in use and where it came from").action((_options, command) => runAction(command, (context) => statusCommand(context)));
|
|
17605
17648
|
program2.command("whoami").description("Show the organization and libraries the API key can access").action((_options, command) => runAction(command, (context) => whoamiCommand(context)));
|
|
@@ -17614,16 +17657,16 @@ var LIBRARY_COLUMNS = [
|
|
|
17614
17657
|
{ header: "TAGS", value: (library) => String((library.tags ?? []).length) }
|
|
17615
17658
|
];
|
|
17616
17659
|
var listOptionsSchema2 = exports_external.object({
|
|
17617
|
-
org: exports_external.string().min(1),
|
|
17618
17660
|
page: exports_external.coerce.number().int().min(1).optional(),
|
|
17619
17661
|
pageSize: exports_external.coerce.number().int().min(1).optional()
|
|
17620
17662
|
});
|
|
17621
17663
|
async function listLibrariesCommand(context, options) {
|
|
17622
17664
|
requireApiKey(context);
|
|
17665
|
+
const organizationId = await context.resolveOrg();
|
|
17623
17666
|
const client = context.clientFactory();
|
|
17624
17667
|
const libraries = await unwrapResult(() => client.GET("/organizations/{organizationId}/libraries", {
|
|
17625
17668
|
params: {
|
|
17626
|
-
path: { organizationId
|
|
17669
|
+
path: { organizationId },
|
|
17627
17670
|
header: VERSION_HEADER,
|
|
17628
17671
|
query: { page: options.page, pageSize: options.pageSize }
|
|
17629
17672
|
}
|
|
@@ -17635,15 +17678,15 @@ async function listLibrariesCommand(context, options) {
|
|
|
17635
17678
|
renderTable(context, libraries, LIBRARY_COLUMNS);
|
|
17636
17679
|
}
|
|
17637
17680
|
var createOptionsSchema = exports_external.object({
|
|
17638
|
-
org: exports_external.string().min(1),
|
|
17639
17681
|
name: exports_external.string().min(1),
|
|
17640
17682
|
slug: exports_external.string().min(1).optional()
|
|
17641
17683
|
});
|
|
17642
17684
|
async function createLibraryCommand(context, options) {
|
|
17643
17685
|
requireApiKey(context);
|
|
17686
|
+
const organizationId = await context.resolveOrg();
|
|
17644
17687
|
const client = context.clientFactory();
|
|
17645
17688
|
const library = await unwrapResult(() => client.POST("/organizations/{organizationId}/libraries", {
|
|
17646
|
-
params: { path: { organizationId
|
|
17689
|
+
params: { path: { organizationId }, header: VERSION_HEADER },
|
|
17647
17690
|
body: { name: options.name, slug: options.slug }
|
|
17648
17691
|
}));
|
|
17649
17692
|
if (context.json) {
|
|
@@ -17657,16 +17700,16 @@ async function createLibraryCommand(context, options) {
|
|
|
17657
17700
|
note(context, "Library created.");
|
|
17658
17701
|
}
|
|
17659
17702
|
var renameOptionsSchema = exports_external.object({
|
|
17660
|
-
org: exports_external.string().min(1),
|
|
17661
|
-
library: exports_external.string().min(1),
|
|
17662
17703
|
name: exports_external.string().min(1)
|
|
17663
17704
|
});
|
|
17664
17705
|
async function renameLibraryCommand(context, options) {
|
|
17665
17706
|
requireApiKey(context);
|
|
17707
|
+
const organizationId = await context.resolveOrg();
|
|
17708
|
+
const libraryId = await context.resolveLibrary();
|
|
17666
17709
|
const client = context.clientFactory();
|
|
17667
17710
|
const library = await unwrapResult(() => client.PATCH("/organizations/{organizationId}/libraries/{libraryId}", {
|
|
17668
17711
|
params: {
|
|
17669
|
-
path: { organizationId
|
|
17712
|
+
path: { organizationId, libraryId },
|
|
17670
17713
|
header: VERSION_HEADER
|
|
17671
17714
|
},
|
|
17672
17715
|
body: { name: options.name }
|
|
@@ -17679,9 +17722,9 @@ async function renameLibraryCommand(context, options) {
|
|
|
17679
17722
|
}
|
|
17680
17723
|
function registerLibraryCommands(program2, runAction) {
|
|
17681
17724
|
const libraries = program2.command("libraries").description("Work with libraries");
|
|
17682
|
-
libraries.command("ls").description("List libraries in
|
|
17683
|
-
libraries.command("create").description("Create a library").requiredOption("--
|
|
17684
|
-
libraries.command("rename").description("Rename
|
|
17725
|
+
libraries.command("ls").description("List libraries in the organization").option("--page <number>", "Page number (1-based)").option("--page-size <number>", "Results per page").action((options, command) => runAction(command, (context) => listLibrariesCommand(context, parseOptions(listOptionsSchema2, options))));
|
|
17726
|
+
libraries.command("create").description("Create a library").requiredOption("--name <name>", "Library name").option("--slug <slug>", "URL slug for the library").action((options, command) => runAction(command, (context) => createLibraryCommand(context, parseOptions(createOptionsSchema, options))));
|
|
17727
|
+
libraries.command("rename").description("Rename the library (the one the key scopes to, or pass --library)").requiredOption("--name <name>", "New library name").action((options, command) => runAction(command, (context) => renameLibraryCommand(context, parseOptions(renameOptionsSchema, options))));
|
|
17685
17728
|
}
|
|
17686
17729
|
|
|
17687
17730
|
// src/commands/orgs.ts
|
|
@@ -17733,16 +17776,16 @@ var TAG_COLUMNS = [
|
|
|
17733
17776
|
{ header: "TYPE", value: (tag) => tag.type ?? "" }
|
|
17734
17777
|
];
|
|
17735
17778
|
var listOptionsSchema3 = exports_external.object({
|
|
17736
|
-
org: exports_external.string().min(1),
|
|
17737
|
-
library: exports_external.string().min(1),
|
|
17738
17779
|
limit: exports_external.coerce.number().int().min(1).optional()
|
|
17739
17780
|
});
|
|
17740
17781
|
async function listTagsCommand(context, options) {
|
|
17741
17782
|
requireApiKey(context);
|
|
17783
|
+
const organizationId = await context.resolveOrg();
|
|
17784
|
+
const libraryId = await context.resolveLibrary();
|
|
17742
17785
|
const client = context.clientFactory();
|
|
17743
17786
|
const tags = await unwrapResult(() => client.GET("/organizations/{organizationId}/libraries/{libraryId}/tags", {
|
|
17744
17787
|
params: {
|
|
17745
|
-
path: { organizationId
|
|
17788
|
+
path: { organizationId, libraryId },
|
|
17746
17789
|
header: VERSION_HEADER,
|
|
17747
17790
|
query: { limit: options.limit }
|
|
17748
17791
|
}
|
|
@@ -17754,53 +17797,54 @@ async function listTagsCommand(context, options) {
|
|
|
17754
17797
|
renderTable(context, tags, TAG_COLUMNS);
|
|
17755
17798
|
}
|
|
17756
17799
|
var mutateOptionsSchema = exports_external.object({
|
|
17757
|
-
org: exports_external.string().min(1),
|
|
17758
|
-
library: exports_external.string().min(1),
|
|
17759
|
-
asset: exports_external.array(exports_external.string().min(1)).min(1),
|
|
17760
17800
|
tag: exports_external.array(exports_external.string().min(1)).min(1)
|
|
17761
17801
|
});
|
|
17762
|
-
async function tagAssetsCommand(context, options) {
|
|
17802
|
+
async function tagAssetsCommand(context, assetIds, options) {
|
|
17803
|
+
if (assetIds.length === 0)
|
|
17804
|
+
throw new UsageError("Provide at least one asset id.");
|
|
17763
17805
|
requireApiKey(context);
|
|
17806
|
+
const organizationId = await context.resolveOrg();
|
|
17807
|
+
const libraryId = await context.resolveLibrary();
|
|
17764
17808
|
const client = context.clientFactory();
|
|
17765
17809
|
const result = await unwrapResult(() => client.POST("/organizations/{organizationId}/libraries/{libraryId}/assets/tag", {
|
|
17766
|
-
params: {
|
|
17767
|
-
|
|
17768
|
-
header: VERSION_HEADER
|
|
17769
|
-
},
|
|
17770
|
-
body: { assetIds: options.asset, tags: options.tag }
|
|
17810
|
+
params: { path: { organizationId, libraryId }, header: VERSION_HEADER },
|
|
17811
|
+
body: { assetIds, tags: options.tag }
|
|
17771
17812
|
}));
|
|
17772
17813
|
if (context.json) {
|
|
17773
17814
|
printJson(context, result);
|
|
17774
17815
|
return;
|
|
17775
17816
|
}
|
|
17776
|
-
note(context, `Tagged ${
|
|
17817
|
+
note(context, `Tagged ${assetIds.length} asset(s) with ${options.tag.join(", ")}.`);
|
|
17777
17818
|
}
|
|
17778
|
-
async function untagAssetsCommand(context, options) {
|
|
17819
|
+
async function untagAssetsCommand(context, assetIds, options) {
|
|
17820
|
+
if (assetIds.length === 0)
|
|
17821
|
+
throw new UsageError("Provide at least one asset id.");
|
|
17779
17822
|
requireApiKey(context);
|
|
17823
|
+
const organizationId = await context.resolveOrg();
|
|
17824
|
+
const libraryId = await context.resolveLibrary();
|
|
17780
17825
|
const client = context.clientFactory();
|
|
17781
17826
|
const result = await unwrapResult(() => client.POST("/organizations/{organizationId}/libraries/{libraryId}/assets/untag", {
|
|
17782
|
-
params: {
|
|
17783
|
-
|
|
17784
|
-
header: VERSION_HEADER
|
|
17785
|
-
},
|
|
17786
|
-
body: { assetIds: options.asset, tags: options.tag }
|
|
17827
|
+
params: { path: { organizationId, libraryId }, header: VERSION_HEADER },
|
|
17828
|
+
body: { assetIds, tags: options.tag }
|
|
17787
17829
|
}));
|
|
17788
17830
|
if (context.json) {
|
|
17789
17831
|
printJson(context, result);
|
|
17790
17832
|
return;
|
|
17791
17833
|
}
|
|
17792
|
-
note(context, `Removed ${options.tag.join(", ")} from ${
|
|
17834
|
+
note(context, `Removed ${options.tag.join(", ")} from ${assetIds.length} asset(s).`);
|
|
17793
17835
|
}
|
|
17794
17836
|
function registerTagCommands(program2, runAction) {
|
|
17795
17837
|
const tags = program2.command("tags").description("Work with tags in a library");
|
|
17796
|
-
tags.command("ls").description("List tags in
|
|
17797
|
-
tags.command("add").description("Add tags to assets").
|
|
17798
|
-
tags.command("rm").description("Remove tags from assets").
|
|
17838
|
+
tags.command("ls").description("List tags in the library").option("--limit <number>", "Maximum number of tags to return").action((options, command) => runAction(command, (context) => listTagsCommand(context, parseOptions(listOptionsSchema3, options))));
|
|
17839
|
+
tags.command("add").description("Add tags to assets").argument("<assetIds...>", "Asset ids to tag").requiredOption("--tag <tag...>", "Tags to add (repeatable)").action((assetIds, options, command) => runAction(command, (context) => tagAssetsCommand(context, assetIds, parseOptions(mutateOptionsSchema, options))));
|
|
17840
|
+
tags.command("rm").description("Remove tags from assets").argument("<assetIds...>", "Asset ids to untag").requiredOption("--tag <tag...>", "Tags to remove (repeatable)").action((assetIds, options, command) => runAction(command, (context) => untagAssetsCommand(context, assetIds, parseOptions(mutateOptionsSchema, options))));
|
|
17799
17841
|
}
|
|
17800
17842
|
|
|
17801
17843
|
// src/index.ts
|
|
17802
17844
|
var globalOptionsSchema = exports_external.object({
|
|
17803
17845
|
apiKey: exports_external.string().optional(),
|
|
17846
|
+
org: exports_external.string().optional(),
|
|
17847
|
+
library: exports_external.string().optional(),
|
|
17804
17848
|
json: exports_external.boolean().optional(),
|
|
17805
17849
|
verbose: exports_external.boolean().optional()
|
|
17806
17850
|
});
|
|
@@ -17830,7 +17874,7 @@ function exitCodeForCommanderError(error51) {
|
|
|
17830
17874
|
return EXIT_CODES.generic;
|
|
17831
17875
|
}
|
|
17832
17876
|
var program2 = new Command;
|
|
17833
|
-
program2.name("raster").description("Command-line client for the Raster API").version(`${package_default.version} (Api-Version ${API_VERSION})`, "-V, --version", "Print the CLI version and the pinned Api-Version").option("--api-key <key>", "API key (overrides RASTER_API_KEY and the config file)").option("--json", "Print machine-readable JSON to stdout").option("--verbose", "Log requests to stderr (keys masked)").exitOverride();
|
|
17877
|
+
program2.name("raster").description("Command-line client for the Raster API").version(`${package_default.version} (Api-Version ${API_VERSION})`, "-V, --version", "Print the CLI version and the pinned Api-Version").option("--api-key <key>", "API key (overrides RASTER_API_KEY and the config file)").option("--org <organizationId>", "Organization id (derived from the API key when omitted)").option("--library <libraryId>", "Library id (derived from the API key when it has one library)").option("--json", "Print machine-readable JSON to stdout").option("--verbose", "Log requests to stderr (keys masked)").exitOverride();
|
|
17834
17878
|
registerAuthCommands(program2, runAction);
|
|
17835
17879
|
registerLibraryCommands(program2, runAction);
|
|
17836
17880
|
registerAssetCommands(program2, runAction);
|