@jclvsh/dropspace 2.0.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.
Files changed (40) hide show
  1. package/README.md +273 -0
  2. package/dist/cli-utils.d.ts +4 -0
  3. package/dist/cli-utils.js +31 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +31 -0
  6. package/dist/client.d.ts +11 -0
  7. package/dist/client.js +110 -0
  8. package/dist/commands/connections.d.ts +3 -0
  9. package/dist/commands/connections.js +23 -0
  10. package/dist/commands/dropspace.d.ts +3 -0
  11. package/dist/commands/dropspace.js +15 -0
  12. package/dist/commands/keys.d.ts +3 -0
  13. package/dist/commands/keys.js +70 -0
  14. package/dist/commands/launches.d.ts +3 -0
  15. package/dist/commands/launches.js +263 -0
  16. package/dist/commands/personas.d.ts +3 -0
  17. package/dist/commands/personas.js +116 -0
  18. package/dist/commands/usage.d.ts +3 -0
  19. package/dist/commands/usage.js +15 -0
  20. package/dist/commands/webhooks.d.ts +3 -0
  21. package/dist/commands/webhooks.js +108 -0
  22. package/dist/index.d.ts +2 -0
  23. package/dist/index.js +25 -0
  24. package/dist/tools/connections.d.ts +3 -0
  25. package/dist/tools/connections.js +30 -0
  26. package/dist/tools/dropspace.d.ts +3 -0
  27. package/dist/tools/dropspace.js +21 -0
  28. package/dist/tools/keys.d.ts +3 -0
  29. package/dist/tools/keys.js +107 -0
  30. package/dist/tools/launches.d.ts +3 -0
  31. package/dist/tools/launches.js +492 -0
  32. package/dist/tools/personas.d.ts +3 -0
  33. package/dist/tools/personas.js +152 -0
  34. package/dist/tools/usage.d.ts +3 -0
  35. package/dist/tools/usage.js +21 -0
  36. package/dist/tools/webhooks.d.ts +3 -0
  37. package/dist/tools/webhooks.js +183 -0
  38. package/dist/types.d.ts +257 -0
  39. package/dist/types.js +1 -0
  40. package/package.json +33 -0
package/README.md ADDED
@@ -0,0 +1,273 @@
1
+ # @jclvsh/dropspace
2
+
3
+ MCP server and CLI for the [Dropspace](https://dropspace.dev) API. Lets AI agents (Claude Code, Cursor) and humans manage launches, personas, platform connections, API keys, and webhooks.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npx @jclvsh/dropspace
9
+ ```
10
+
11
+ Or install globally:
12
+
13
+ ```bash
14
+ npm install -g @jclvsh/dropspace
15
+ ```
16
+
17
+ ## Configuration
18
+
19
+ ### Environment Variables
20
+
21
+ | Variable | Required | Description |
22
+ | ------------------- | -------- | --------------------------------------------------- |
23
+ | `DROPSPACE_API_KEY` | Yes | Your Dropspace API key |
24
+ | `DROPSPACE_API_URL` | No | API base URL (default: `https://api.dropspace.dev`) |
25
+
26
+ ### Claude Code
27
+
28
+ Add to your `.claude/settings.json`:
29
+
30
+ ```json
31
+ {
32
+ "mcpServers": {
33
+ "dropspace": {
34
+ "command": "npx",
35
+ "args": ["-y", "@jclvsh/dropspace"],
36
+ "env": {
37
+ "DROPSPACE_API_KEY": "ds_live_your_key_here"
38
+ }
39
+ }
40
+ }
41
+ }
42
+ ```
43
+
44
+ ### Cursor
45
+
46
+ Add to your `.cursor/mcp.json`:
47
+
48
+ ```json
49
+ {
50
+ "mcpServers": {
51
+ "dropspace": {
52
+ "command": "npx",
53
+ "args": ["-y", "@jclvsh/dropspace"],
54
+ "env": {
55
+ "DROPSPACE_API_KEY": "ds_live_your_key_here"
56
+ }
57
+ }
58
+ }
59
+ }
60
+ ```
61
+
62
+ ## Available Tools
63
+
64
+ ### Launches
65
+
66
+ | Tool | Description |
67
+ | ---------------------- | -------------------------------------------------------------- |
68
+ | `list_launches` | List your launches with pagination |
69
+ | `create_launch` | Create a new launch with content, media, and account selection |
70
+ | `get_launch` | Get a launch by ID with posting status |
71
+ | `update_launch` | Update a launch's schedule, status, content, or media |
72
+ | `delete_launch` | Delete a launch |
73
+ | `publish_launch` | Publish a launch to all configured platforms |
74
+ | `retry_launch` | Retry failed platforms for a launch |
75
+ | `generate_content` | Generate AI content and video scripts for a launch |
76
+ | `retry_launch_content` | Retry AI content generation for failed platforms |
77
+ | `get_launch_analytics` | Get publishing analytics with per-post engagement metrics |
78
+ | `get_launch_status` | Get detailed posting status with per-platform logs |
79
+
80
+ #### `create_launch` Parameters
81
+
82
+ | Parameter | Type | Required | Description |
83
+ | ----------------------------- | ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
84
+ | `title` | string | Yes | Launch title |
85
+ | `product_description` | string | Yes | Product description |
86
+ | `platforms` | string[] | Yes | Platforms to publish to (1-9) |
87
+ | `product_url` | string | No | Product URL |
88
+ | `scheduled_date` | string | No | ISO 8601 datetime (15+ min in the future) |
89
+ | `persona_id` | string | No | Persona ID for tone/style |
90
+ | `dropspace_platforms` | string[] | No | Platforms to post via official dropspace accounts |
91
+ | `media_mode` | string | No | `"images"` or `"video"` |
92
+ | `user_platform_accounts` | object | No | Map of platform key to token_id (UUID). Simple keys: `twitter`, `reddit`, `instagram`, `tiktok`. LinkedIn: `linkedin:personal` or `linkedin:organization:<org_id>`. Facebook: `facebook:page:<page_id>` |
93
+ | `platform_contents` | object | No | Per-platform content (mutually exclusive with `custom_content`) |
94
+ | `custom_content` | string \| string[] | No | Single content for all platforms, or array of tweets for twitter thread mode (mutually exclusive with `platform_contents`) |
95
+ | `custom_content_reddit_title` | string | No | Reddit title (required with `custom_content` + reddit) |
96
+ | `media` | object[] | No | Inline media, URL or base64 (1-10 items, mutually exclusive with `media_assets`) |
97
+ | `media_assets` | object[] | No | Pre-uploaded media references (mutually exclusive with `media`) |
98
+ | `media_attach_platforms` | string[] | No | Platforms to attach media to |
99
+ | `generate_ai_videos` | string[] | No | Auto-generate AI videos (`"instagram"`, `"tiktok"`) |
100
+
101
+ #### `update_launch` Parameters
102
+
103
+ | Parameter | Type | Required | Description |
104
+ | ------------------------ | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
105
+ | `id` | string | Yes | Launch ID |
106
+ | `scheduled_date` | string \| null | No | ISO 8601 datetime or null to clear |
107
+ | `status` | string | No | `"draft"`, `"manual"`, `"trigger"`, `"scheduled"`, `"cancelled"` |
108
+ | `platform_contents` | object | No | Per-platform content overrides |
109
+ | `dropspace_platforms` | string[] | No | Official dropspace account platforms |
110
+ | `user_platform_accounts` | object | No | Map of platform key to token_id (UUID). Simple keys: `twitter`, `reddit`, `instagram`, `tiktok`. LinkedIn: `linkedin:personal` or `linkedin:organization:<org_id>`. Facebook: `facebook:page:<page_id>` |
111
+ | `media` | object[] | No | Inline media (URL or base64, 1-10 items) |
112
+ | `media_assets` | object[] | No | Pre-uploaded media references |
113
+ | `media_attach_platforms` | string[] | No | Platforms to attach media to |
114
+ | `media_mode` | string | No | `"images"` or `"video"` |
115
+
116
+ #### `generate_content` Parameters
117
+
118
+ | Parameter | Type | Required | Description |
119
+ | ------------------------ | -------- | -------- | ------------------------------------------------------------------- |
120
+ | `id` | string | Yes | Launch ID |
121
+ | `platforms` | string[] | No | Platforms to generate for (defaults to all) |
122
+ | `generate_video_scripts` | string[] | No | Platforms to generate video scripts for (`"instagram"`, `"tiktok"`) |
123
+
124
+ ### Personas
125
+
126
+ | Tool | Description |
127
+ | ----------------- | ------------------------------------------------ |
128
+ | `list_personas` | List your personas |
129
+ | `create_persona` | Create a new persona for content tone/style |
130
+ | `get_persona` | Get a persona by ID with analysis details |
131
+ | `update_persona` | Update a persona's name or writing samples |
132
+ | `delete_persona` | Delete a persona |
133
+ | `analyze_persona` | Trigger AI analysis of a persona's writing style |
134
+
135
+ #### `analyze_persona` Parameters
136
+
137
+ | Parameter | Type | Required | Description |
138
+ | ------------------------ | ------------- | -------- | ------------------------------------------ |
139
+ | `id` | string (UUID) | Yes | Persona ID |
140
+ | `platforms` | string[] | No | Specific platforms to analyze samples from |
141
+ | `include_custom_samples` | boolean | No | Include custom writing samples in analysis |
142
+
143
+ #### `update_persona` Parameters
144
+
145
+ | Parameter | Type | Required | Description |
146
+ | ------------------- | ------ | -------- | ----------------------------------- |
147
+ | `id` | string | Yes | Persona ID |
148
+ | `name` | string | No | New persona name (1-100 characters) |
149
+ | `custom_samples` | array | No | Custom writing samples (max 50) |
150
+ | `twitter_samples` | array | No | Twitter writing samples (max 50) |
151
+ | `reddit_samples` | array | No | Reddit writing samples (max 50) |
152
+ | `facebook_samples` | array | No | Facebook writing samples (max 50) |
153
+ | `instagram_samples` | array | No | Instagram writing samples (max 50) |
154
+ | `tiktok_samples` | array | No | TikTok writing samples (max 50) |
155
+ | `linkedin_samples` | array | No | LinkedIn writing samples (max 50) |
156
+
157
+ ### Connections
158
+
159
+ | Tool | Description |
160
+ | ------------------ | ----------------------------------------- |
161
+ | `list_connections` | List your connected social media accounts |
162
+
163
+ ### Posts
164
+
165
+ | Tool | Description |
166
+ | ------------------ | ------------------------------------------------------ |
167
+ | `delete_post` | Delete a single published post from its platform |
168
+ | `delete_all_posts` | Delete all published posts for a launch from platforms |
169
+
170
+ ### API Keys
171
+
172
+ | Tool | Description |
173
+ | --------------------- | -------------------------------------------------- |
174
+ | `get_current_api_key` | Get the current API key's info (no scope required) |
175
+ | `list_api_keys` | List your API keys (requires admin scope) |
176
+ | `create_api_key` | Create a new API key (raw key returned once) |
177
+ | `rename_api_key` | Rename an API key |
178
+ | `revoke_api_key` | Permanently revoke an API key |
179
+
180
+ #### `create_api_key` Parameters
181
+
182
+ | Parameter | Type | Required | Description |
183
+ | --------- | -------- | -------- | ---------------------------------------------------------------------------------------------- |
184
+ | `name` | string | Yes | Key name (1-100 characters) |
185
+ | `scopes` | string[] | No | Permission scopes (defaults to all): `read`, `write`, `delete`, `publish`, `generate`, `admin` |
186
+
187
+ ### Webhooks
188
+
189
+ | Tool | Description |
190
+ | ------------------------- | ------------------------------------------------------------ |
191
+ | `list_webhooks` | List your webhooks |
192
+ | `create_webhook` | Create a webhook endpoint (secret returned once) |
193
+ | `get_webhook` | Get a webhook by ID |
194
+ | `update_webhook` | Update a webhook's URL, events, or active status |
195
+ | `delete_webhook` | Delete a webhook |
196
+ | `rotate_webhook_secret` | Rotate a webhook's signing secret (new secret returned once) |
197
+ | `list_webhook_deliveries` | List delivery attempts for a webhook |
198
+
199
+ #### `create_webhook` Parameters
200
+
201
+ | Parameter | Type | Required | Description |
202
+ | --------- | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
203
+ | `url` | string | Yes | HTTPS webhook URL |
204
+ | `events` | string[] | Yes | Events to subscribe to: `launch.completed`, `launch.failed`, `launch.partial`, `media.ready`, `persona.analyzed`, `post.deleted` |
205
+
206
+ #### `update_webhook` Parameters
207
+
208
+ | Parameter | Type | Required | Description |
209
+ | --------- | ------------- | -------- | ----------------------------- |
210
+ | `id` | string (UUID) | Yes | Webhook ID |
211
+ | `url` | string | No | New HTTPS webhook URL |
212
+ | `events` | string[] | No | New events to subscribe to |
213
+ | `active` | boolean | No | Enable or disable the webhook |
214
+
215
+ ### Dropspace
216
+
217
+ | Tool | Description |
218
+ | ---------------------- | -------------------------------------------------------- |
219
+ | `get_dropspace_status` | Check which platforms have a connected dropspace account |
220
+
221
+ ### Usage
222
+
223
+ | Tool | Description |
224
+ | ----------- | ------------------------------------------------------- |
225
+ | `get_usage` | Get your current plan, usage limits, and billing period |
226
+
227
+ ## API Key & Scopes
228
+
229
+ Generate an API key at [dropspace.dev/settings](https://dropspace.dev/settings) under the API section.
230
+
231
+ API keys support scoped permissions:
232
+
233
+ | Scope | Access |
234
+ | ---------- | ---------------------------------------------------------------------- |
235
+ | `read` | List and read launches, personas, connections, dropspace status |
236
+ | `write` | Create and update launches, personas |
237
+ | `delete` | Delete launches, personas |
238
+ | `publish` | Publish and retry launches |
239
+ | `generate` | Generate AI content, retry content generation |
240
+ | `admin` | Manage API keys and webhooks |
241
+
242
+ ### Recommended Scopes by Use Case
243
+
244
+ | Use Case | Recommended Scopes |
245
+ | ---------------- | --------------------------------------------------------- |
246
+ | AI agents / MCP | `read`, `write`, `generate` |
247
+ | CI/CD publishing | `read`, `publish` |
248
+ | Monitoring | `read` |
249
+ | Full management | `read`, `write`, `delete`, `publish`, `generate`, `admin` |
250
+
251
+ ## Webhook Events
252
+
253
+ | Event | Description |
254
+ | ------------------ | ------------------------------------------------------------ |
255
+ | `launch.completed` | All platforms finished posting successfully |
256
+ | `launch.failed` | Launch posting failed on all platforms |
257
+ | `launch.partial` | Launch posting succeeded on some platforms, failed on others |
258
+ | `media.ready` | Media generation job completed |
259
+ | `persona.analyzed` | Persona AI analysis completed |
260
+ | `post.deleted` | A published post was deleted from its platform |
261
+
262
+ ## Development
263
+
264
+ ```bash
265
+ # Install dependencies
266
+ npm install
267
+
268
+ # Build
269
+ npm run build
270
+
271
+ # Run
272
+ DROPSPACE_API_KEY=ds_live_... npm start
273
+ ```
@@ -0,0 +1,4 @@
1
+ export declare function formatOutput(data: unknown, format?: string): void;
2
+ export declare function handleError(error: unknown): never;
3
+ export declare function getFormat(opts: Record<string, unknown>): string;
4
+ export declare function parseList(value: string): string[];
@@ -0,0 +1,31 @@
1
+ export function formatOutput(data, format = "json") {
2
+ if (format === "table" && typeof data === "object" && data !== null) {
3
+ const obj = data;
4
+ if (Array.isArray(obj.data)) {
5
+ console.table(obj.data);
6
+ if (obj.pagination) {
7
+ const p = obj.pagination;
8
+ console.error(`\npage ${p.page}/${p.total_pages} (${p.total} total)`);
9
+ }
10
+ return;
11
+ }
12
+ if (obj.data && typeof obj.data === "object") {
13
+ console.log(JSON.stringify(obj.data, null, 2));
14
+ return;
15
+ }
16
+ }
17
+ console.log(JSON.stringify(data, null, 2));
18
+ }
19
+ export function handleError(error) {
20
+ const message = error instanceof Error ? error.message : String(error);
21
+ console.error(`error: ${message}`);
22
+ process.exit(1);
23
+ }
24
+ export function getFormat(opts) {
25
+ if (opts.json)
26
+ return "json";
27
+ return opts.format || "json";
28
+ }
29
+ export function parseList(value) {
30
+ return value.split(",").map((s) => s.trim()).filter(Boolean);
31
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { DropspaceClient } from "./client.js";
4
+ import { handleError } from "./cli-utils.js";
5
+ import { registerLaunchCommands } from "./commands/launches.js";
6
+ import { registerPersonaCommands } from "./commands/personas.js";
7
+ import { registerConnectionCommands } from "./commands/connections.js";
8
+ import { registerKeyCommands } from "./commands/keys.js";
9
+ import { registerWebhookCommands } from "./commands/webhooks.js";
10
+ import { registerDropspaceCommands } from "./commands/dropspace.js";
11
+ import { registerUsageCommands } from "./commands/usage.js";
12
+ const program = new Command()
13
+ .name("dropspace")
14
+ .description("dropspace CLI - manage launches, personas, and more")
15
+ .version("2.0.0")
16
+ .option("--json", "output as JSON (default)")
17
+ .option("--format <fmt>", "output format: json, table", "json");
18
+ try {
19
+ const client = new DropspaceClient();
20
+ registerLaunchCommands(program, client);
21
+ registerPersonaCommands(program, client);
22
+ registerConnectionCommands(program, client);
23
+ registerKeyCommands(program, client);
24
+ registerWebhookCommands(program, client);
25
+ registerDropspaceCommands(program, client);
26
+ registerUsageCommands(program, client);
27
+ await program.parseAsync(process.argv);
28
+ }
29
+ catch (error) {
30
+ handleError(error);
31
+ }
@@ -0,0 +1,11 @@
1
+ export declare class DropspaceClient {
2
+ private apiKey;
3
+ private baseUrl;
4
+ constructor();
5
+ get<T>(path: string, params?: Record<string, string>): Promise<T>;
6
+ post<T>(path: string, body?: unknown): Promise<T>;
7
+ patch<T>(path: string, body: unknown): Promise<T>;
8
+ delete(path: string): Promise<void>;
9
+ private request;
10
+ private handleError;
11
+ }
package/dist/client.js ADDED
@@ -0,0 +1,110 @@
1
+ const REQUEST_TIMEOUT_MS = 30_000;
2
+ export class DropspaceClient {
3
+ apiKey;
4
+ baseUrl;
5
+ constructor() {
6
+ const apiKey = process.env.DROPSPACE_API_KEY;
7
+ if (!apiKey) {
8
+ throw new Error("DROPSPACE_API_KEY environment variable is required");
9
+ }
10
+ if (!apiKey.startsWith("ds_live_")) {
11
+ throw new Error("DROPSPACE_API_KEY must start with 'ds_live_'. Get one at https://dropspace.dev/settings");
12
+ }
13
+ this.apiKey = apiKey;
14
+ this.baseUrl = (process.env.DROPSPACE_API_URL || "https://api.dropspace.dev").replace(/\/$/, "");
15
+ }
16
+ async get(path, params) {
17
+ const url = new URL(`${this.baseUrl}${path}`);
18
+ if (params) {
19
+ for (const [key, value] of Object.entries(params)) {
20
+ if (value !== undefined && value !== "") {
21
+ url.searchParams.set(key, value);
22
+ }
23
+ }
24
+ }
25
+ return this.request(url.toString(), { method: "GET" });
26
+ }
27
+ async post(path, body) {
28
+ return this.request(`${this.baseUrl}${path}`, {
29
+ method: "POST",
30
+ headers: { "Content-Type": "application/json" },
31
+ body: body !== undefined ? JSON.stringify(body) : undefined,
32
+ });
33
+ }
34
+ async patch(path, body) {
35
+ return this.request(`${this.baseUrl}${path}`, {
36
+ method: "PATCH",
37
+ headers: { "Content-Type": "application/json" },
38
+ body: JSON.stringify(body),
39
+ });
40
+ }
41
+ async delete(path) {
42
+ try {
43
+ const response = await fetch(`${this.baseUrl}${path}`, {
44
+ method: "DELETE",
45
+ headers: { Authorization: `Bearer ${this.apiKey}` },
46
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
47
+ });
48
+ if (!response.ok && response.status !== 204) {
49
+ await this.handleError(response);
50
+ }
51
+ }
52
+ catch (error) {
53
+ if (error instanceof Error && error.name === "TimeoutError") {
54
+ throw new Error("request timed out after 30s");
55
+ }
56
+ throw error;
57
+ }
58
+ }
59
+ async request(url, init) {
60
+ let response;
61
+ try {
62
+ response = await fetch(url, {
63
+ ...init,
64
+ headers: {
65
+ ...(init.headers || {}),
66
+ Authorization: `Bearer ${this.apiKey}`,
67
+ },
68
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
69
+ });
70
+ }
71
+ catch (error) {
72
+ if (error instanceof Error && error.name === "TimeoutError") {
73
+ throw new Error("request timed out after 30s");
74
+ }
75
+ if (error instanceof TypeError) {
76
+ throw new Error(`network error: ${error.message}. check DROPSPACE_API_URL and your connection`);
77
+ }
78
+ throw error;
79
+ }
80
+ if (!response.ok) {
81
+ await this.handleError(response);
82
+ }
83
+ return (await response.json());
84
+ }
85
+ async handleError(response) {
86
+ let errorMessage;
87
+ try {
88
+ const body = (await response.json());
89
+ if (body.error) {
90
+ errorMessage = `[${body.error.code}] ${body.error.message}`;
91
+ if (body.error.field) {
92
+ errorMessage += ` (field: ${body.error.field})`;
93
+ }
94
+ }
95
+ else {
96
+ errorMessage = `API error: ${response.status} ${response.statusText}`;
97
+ }
98
+ }
99
+ catch {
100
+ errorMessage = `API error: ${response.status} ${response.statusText}`;
101
+ }
102
+ if (response.status === 429) {
103
+ const retryAfter = response.headers.get("Retry-After");
104
+ if (retryAfter) {
105
+ errorMessage += ` — retry after ${retryAfter}s`;
106
+ }
107
+ }
108
+ throw new Error(errorMessage);
109
+ }
110
+ }
@@ -0,0 +1,3 @@
1
+ import type { Command } from "commander";
2
+ import type { DropspaceClient } from "../client.js";
3
+ export declare function registerConnectionCommands(program: Command, client: DropspaceClient): void;
@@ -0,0 +1,23 @@
1
+ import { formatOutput, handleError, getFormat } from "../cli-utils.js";
2
+ export function registerConnectionCommands(program, client) {
3
+ const connections = program.command("connections").alias("c").description("manage platform connections");
4
+ connections
5
+ .command("list")
6
+ .description("list connected social media accounts")
7
+ .option("-p, --page <n>", "page number", "1")
8
+ .option("-s, --page-size <n>", "items per page (max 100)", "50")
9
+ .action(async (opts) => {
10
+ try {
11
+ const params = {};
12
+ if (opts.page)
13
+ params.page = opts.page;
14
+ if (opts.pageSize)
15
+ params.page_size = opts.pageSize;
16
+ const result = await client.get("/connections", params);
17
+ formatOutput(result, getFormat(program.opts()));
18
+ }
19
+ catch (error) {
20
+ handleError(error);
21
+ }
22
+ });
23
+ }
@@ -0,0 +1,3 @@
1
+ import type { Command } from "commander";
2
+ import type { DropspaceClient } from "../client.js";
3
+ export declare function registerDropspaceCommands(program: Command, client: DropspaceClient): void;
@@ -0,0 +1,15 @@
1
+ import { formatOutput, handleError, getFormat } from "../cli-utils.js";
2
+ export function registerDropspaceCommands(program, client) {
3
+ program
4
+ .command("status")
5
+ .description("check dropspace official account platform connections")
6
+ .action(async () => {
7
+ try {
8
+ const result = await client.get("/dropspace/status");
9
+ formatOutput(result, getFormat(program.opts()));
10
+ }
11
+ catch (error) {
12
+ handleError(error);
13
+ }
14
+ });
15
+ }
@@ -0,0 +1,3 @@
1
+ import type { Command } from "commander";
2
+ import type { DropspaceClient } from "../client.js";
3
+ export declare function registerKeyCommands(program: Command, client: DropspaceClient): void;
@@ -0,0 +1,70 @@
1
+ import { formatOutput, handleError, getFormat, parseList } from "../cli-utils.js";
2
+ export function registerKeyCommands(program, client) {
3
+ const keys = program.command("keys").alias("k").description("manage API keys");
4
+ keys
5
+ .command("me")
6
+ .description("get current API key info")
7
+ .action(async () => {
8
+ try {
9
+ const result = await client.get("/keys/me");
10
+ formatOutput(result, getFormat(program.opts()));
11
+ }
12
+ catch (error) {
13
+ handleError(error);
14
+ }
15
+ });
16
+ keys
17
+ .command("list")
18
+ .description("list API keys (requires admin scope)")
19
+ .action(async () => {
20
+ try {
21
+ const result = await client.get("/keys");
22
+ formatOutput(result, getFormat(program.opts()));
23
+ }
24
+ catch (error) {
25
+ handleError(error);
26
+ }
27
+ });
28
+ keys
29
+ .command("create")
30
+ .description("create a new API key (requires admin scope)")
31
+ .requiredOption("-n, --name <name>", "key name")
32
+ .option("--scopes <list>", "comma-separated scopes: read,write,delete,publish,generate,admin", parseList)
33
+ .action(async (opts) => {
34
+ try {
35
+ const body = { name: opts.name };
36
+ if (opts.scopes)
37
+ body.scopes = opts.scopes;
38
+ const result = await client.post("/keys", body);
39
+ formatOutput(result, getFormat(program.opts()));
40
+ }
41
+ catch (error) {
42
+ handleError(error);
43
+ }
44
+ });
45
+ keys
46
+ .command("rename <id>")
47
+ .description("rename an API key (requires admin scope)")
48
+ .requiredOption("-n, --name <name>", "new key name")
49
+ .action(async (id, opts) => {
50
+ try {
51
+ const result = await client.patch(`/keys/${id}`, { name: opts.name });
52
+ formatOutput(result, getFormat(program.opts()));
53
+ }
54
+ catch (error) {
55
+ handleError(error);
56
+ }
57
+ });
58
+ keys
59
+ .command("revoke <id>")
60
+ .description("permanently revoke an API key (requires admin scope)")
61
+ .action(async (id) => {
62
+ try {
63
+ await client.delete(`/keys/${id}`);
64
+ console.log("api key revoked");
65
+ }
66
+ catch (error) {
67
+ handleError(error);
68
+ }
69
+ });
70
+ }
@@ -0,0 +1,3 @@
1
+ import type { Command } from "commander";
2
+ import type { DropspaceClient } from "../client.js";
3
+ export declare function registerLaunchCommands(program: Command, client: DropspaceClient): void;