@dropthis/cli 0.26.0 → 0.28.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/dist/cli.cjs +209 -8
- package/dist/cli.cjs.map +1 -1
- package/node_modules/@dropthis/node/README.md +63 -1
- package/node_modules/@dropthis/node/dist/{drops-gUdVVDX6.d.cts → drops-YhYy2f6R.d.cts} +69 -7
- package/node_modules/@dropthis/node/dist/{drops-gUdVVDX6.d.ts → drops-YhYy2f6R.d.ts} +69 -7
- package/node_modules/@dropthis/node/dist/edge.cjs +26 -7
- package/node_modules/@dropthis/node/dist/edge.cjs.map +1 -1
- package/node_modules/@dropthis/node/dist/edge.d.cts +3 -1
- package/node_modules/@dropthis/node/dist/edge.d.ts +3 -1
- package/node_modules/@dropthis/node/dist/edge.mjs +26 -7
- package/node_modules/@dropthis/node/dist/edge.mjs.map +1 -1
- package/node_modules/@dropthis/node/dist/index.cjs +62 -9
- package/node_modules/@dropthis/node/dist/index.cjs.map +1 -1
- package/node_modules/@dropthis/node/dist/index.d.cts +18 -3
- package/node_modules/@dropthis/node/dist/index.d.ts +18 -3
- package/node_modules/@dropthis/node/dist/index.mjs +61 -9
- package/node_modules/@dropthis/node/dist/index.mjs.map +1 -1
- package/node_modules/@dropthis/node/package.json +1 -1
- package/package.json +2 -2
package/dist/cli.cjs
CHANGED
|
@@ -218,6 +218,7 @@ function normalizeApiErrorCode(error2) {
|
|
|
218
218
|
}
|
|
219
219
|
function nextActionForApiError(error2, mode = "json") {
|
|
220
220
|
const cliHint = cliNextAction(error2);
|
|
221
|
+
if (error2.code === "workspace_choice_required" && cliHint) return cliHint;
|
|
221
222
|
if (mode === "human" && cliHint) return cliHint;
|
|
222
223
|
if (error2.suggestion) return error2.suggestion;
|
|
223
224
|
if (cliHint) return cliHint;
|
|
@@ -229,9 +230,23 @@ function nextActionForApiError(error2, mode = "json") {
|
|
|
229
230
|
}
|
|
230
231
|
return "Fix the request or retry after checking the drop state.";
|
|
231
232
|
}
|
|
233
|
+
function workspaceChoiceSlugs(error2) {
|
|
234
|
+
const body = error2.body;
|
|
235
|
+
const raw = body && typeof body === "object" ? body.choices : void 0;
|
|
236
|
+
if (!Array.isArray(raw)) return [];
|
|
237
|
+
return raw.map(
|
|
238
|
+
(c) => c && typeof c === "object" ? c.slug : void 0
|
|
239
|
+
).filter((s) => typeof s === "string" && s.length > 0);
|
|
240
|
+
}
|
|
232
241
|
function cliNextAction(error2) {
|
|
233
242
|
const uploadNextAction = error2.code ? UPLOAD_NEXT_ACTIONS[error2.code] : void 0;
|
|
234
243
|
if (uploadNextAction) return uploadNextAction;
|
|
244
|
+
if (error2.code === "workspace_choice_required") {
|
|
245
|
+
const slugs = workspaceChoiceSlugs(error2);
|
|
246
|
+
const example = slugs[0] ?? "<slug>";
|
|
247
|
+
const list = slugs.length ? ` Workspaces: ${slugs.join(", ")}.` : "";
|
|
248
|
+
return `This account belongs to more than one workspace \u2014 pick one. Switch it for every later command with: dropthis workspace use ${example} \u2014 or target just this one with: --workspace ${example}.${list}`;
|
|
249
|
+
}
|
|
235
250
|
if (error2.code === "network_error") {
|
|
236
251
|
return "Could not reach the dropthis API \u2014 check your network or DROPTHIS_API_URL.";
|
|
237
252
|
}
|
|
@@ -792,6 +807,32 @@ var COMMAND_ANNOTATIONS = {
|
|
|
792
807
|
auth: "required",
|
|
793
808
|
examples: ["dropthis api-keys create --label CI --json"]
|
|
794
809
|
},
|
|
810
|
+
workspace: {
|
|
811
|
+
auth: "required",
|
|
812
|
+
examples: ["dropthis workspace list --json", "dropthis workspace use acme"]
|
|
813
|
+
},
|
|
814
|
+
"workspace list": {
|
|
815
|
+
auth: "required",
|
|
816
|
+
examples: ["dropthis workspace list --json"]
|
|
817
|
+
},
|
|
818
|
+
"workspace use": {
|
|
819
|
+
auth: "required",
|
|
820
|
+
examples: [
|
|
821
|
+
"dropthis workspace use acme",
|
|
822
|
+
"dropthis workspace use ws_team123"
|
|
823
|
+
]
|
|
824
|
+
},
|
|
825
|
+
keys: {
|
|
826
|
+
auth: "required",
|
|
827
|
+
examples: ["dropthis keys create --service --workspace acme --json"]
|
|
828
|
+
},
|
|
829
|
+
"keys create": {
|
|
830
|
+
auth: "required",
|
|
831
|
+
examples: [
|
|
832
|
+
"dropthis keys create --json",
|
|
833
|
+
"dropthis keys create --service --workspace acme --json"
|
|
834
|
+
]
|
|
835
|
+
},
|
|
795
836
|
login: {
|
|
796
837
|
examples: [
|
|
797
838
|
"dropthis login verify --email user@example.com --otp 123456 --json"
|
|
@@ -932,6 +973,9 @@ function spreadData(data) {
|
|
|
932
973
|
return data && typeof data === "object" ? data : { data };
|
|
933
974
|
}
|
|
934
975
|
|
|
976
|
+
// src/version.ts
|
|
977
|
+
var CLI_VERSION = true ? "0.28.0" : "0.0.0-dev";
|
|
978
|
+
|
|
935
979
|
// src/commands/doctor.ts
|
|
936
980
|
async function runDoctor(_input, deps) {
|
|
937
981
|
const stored = await deps.store.read();
|
|
@@ -942,13 +986,13 @@ async function runDoctor(_input, deps) {
|
|
|
942
986
|
const authSource = credential?.source ?? "missing";
|
|
943
987
|
const storageBackend = stored?.storage ?? "none";
|
|
944
988
|
const pairs = [
|
|
945
|
-
["Version",
|
|
989
|
+
["Version", CLI_VERSION],
|
|
946
990
|
["Auth", authSource],
|
|
947
991
|
["Storage", storageBackend]
|
|
948
992
|
];
|
|
949
993
|
writeKv(deps, pairs, {
|
|
950
994
|
ok: true,
|
|
951
|
-
version:
|
|
995
|
+
version: CLI_VERSION,
|
|
952
996
|
auth: { source: authSource },
|
|
953
997
|
storage: { backend: storageBackend }
|
|
954
998
|
});
|
|
@@ -1496,6 +1540,58 @@ async function runDropsDelete(target, input, deps) {
|
|
|
1496
1540
|
return { exitCode: 0 };
|
|
1497
1541
|
}
|
|
1498
1542
|
|
|
1543
|
+
// src/commands/keys.ts
|
|
1544
|
+
async function runKeysCreate(input, deps) {
|
|
1545
|
+
try {
|
|
1546
|
+
await requireCredential({
|
|
1547
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
1548
|
+
env: deps.env,
|
|
1549
|
+
store: deps.store
|
|
1550
|
+
});
|
|
1551
|
+
} catch {
|
|
1552
|
+
return writeAuthError(deps);
|
|
1553
|
+
}
|
|
1554
|
+
const keyType = input.type ?? "delegated";
|
|
1555
|
+
if (input.workspace && keyType !== "service") {
|
|
1556
|
+
return writeError(
|
|
1557
|
+
deps,
|
|
1558
|
+
"invalid_usage",
|
|
1559
|
+
"--workspace is only valid with --service (it pins a CI service key to one workspace). A delegated login key is account-scoped and switchable \u2014 use `dropthis workspace use <slug>` to change its active workspace."
|
|
1560
|
+
);
|
|
1561
|
+
}
|
|
1562
|
+
if (keyType === "service" && !input.workspace) {
|
|
1563
|
+
return writeError(
|
|
1564
|
+
deps,
|
|
1565
|
+
"invalid_usage",
|
|
1566
|
+
"Service keys must be pinned to a workspace: pass --workspace <slug-or-id>. (A service key is for CI/automation and never switches workspace.)"
|
|
1567
|
+
);
|
|
1568
|
+
}
|
|
1569
|
+
const label = input.label ?? (keyType === "service" ? `Service key${input.workspace ? ` (${input.workspace})` : ""}` : "CLI key");
|
|
1570
|
+
const createInput = {
|
|
1571
|
+
label,
|
|
1572
|
+
type: keyType
|
|
1573
|
+
};
|
|
1574
|
+
if (keyType === "service" && input.workspace) {
|
|
1575
|
+
createInput.workspace = input.workspace;
|
|
1576
|
+
}
|
|
1577
|
+
const result = await deps.client.apiKeys.create(createInput);
|
|
1578
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
1579
|
+
const data = result.data;
|
|
1580
|
+
const pairs = [];
|
|
1581
|
+
if (data.id) pairs.push(["ID", String(data.id)]);
|
|
1582
|
+
if (data.key) pairs.push(["Key", String(data.key)]);
|
|
1583
|
+
if (data.keyLast4) pairs.push(["Last 4", String(data.keyLast4)]);
|
|
1584
|
+
if (data.label) pairs.push(["Label", String(data.label)]);
|
|
1585
|
+
writeKv(deps, pairs, { ok: true, api_key: result.data });
|
|
1586
|
+
if (deps.outputMode === "human") {
|
|
1587
|
+
deps.stderr(
|
|
1588
|
+
`${hint("Store this key now \u2014 it will not be shown again.")}
|
|
1589
|
+
`
|
|
1590
|
+
);
|
|
1591
|
+
}
|
|
1592
|
+
return { exitCode: 0 };
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1499
1595
|
// src/commands/login.ts
|
|
1500
1596
|
var prompts4 = __toESM(require("@clack/prompts"), 1);
|
|
1501
1597
|
async function runLoginInteractive(deps) {
|
|
@@ -1553,7 +1649,10 @@ async function runLoginInteractive(deps) {
|
|
|
1553
1649
|
return { exitCode: exitCodeFor("api_error") };
|
|
1554
1650
|
}
|
|
1555
1651
|
const authedClient = deps.createClient(session.data.token);
|
|
1556
|
-
const apiKey = await authedClient.apiKeys.create({
|
|
1652
|
+
const apiKey = await authedClient.apiKeys.create({
|
|
1653
|
+
label: "CLI",
|
|
1654
|
+
type: "delegated"
|
|
1655
|
+
});
|
|
1557
1656
|
if (apiKey.error) {
|
|
1558
1657
|
prompts4.cancel(apiKey.error.message);
|
|
1559
1658
|
return { exitCode: exitCodeFor("api_error") };
|
|
@@ -1596,7 +1695,10 @@ async function runLoginVerify(input, deps) {
|
|
|
1596
1695
|
return writeApiError(deps, session.error);
|
|
1597
1696
|
}
|
|
1598
1697
|
const authedClient = deps.createClient(session.data.token);
|
|
1599
|
-
const apiKey = await authedClient.apiKeys.create({
|
|
1698
|
+
const apiKey = await authedClient.apiKeys.create({
|
|
1699
|
+
label: "CLI",
|
|
1700
|
+
type: "delegated"
|
|
1701
|
+
});
|
|
1600
1702
|
if (apiKey.error) {
|
|
1601
1703
|
return writeApiError(deps, apiKey.error);
|
|
1602
1704
|
}
|
|
@@ -1804,7 +1906,8 @@ async function parseDropOptions(raw) {
|
|
|
1804
1906
|
...raw.path ? { path: raw.path } : {},
|
|
1805
1907
|
...raw.idempotencyKey ? { idempotencyKey: raw.idempotencyKey } : {},
|
|
1806
1908
|
...raw.shared ? { domain: import_node.SHARED_POOL } : raw.domain ? { domain: raw.domain } : {},
|
|
1807
|
-
...raw.slug ? { slug: raw.slug } : {}
|
|
1909
|
+
...raw.slug ? { slug: raw.slug } : {},
|
|
1910
|
+
...raw.workspace ? { workspace: raw.workspace } : {}
|
|
1808
1911
|
};
|
|
1809
1912
|
}
|
|
1810
1913
|
function parseJsonObject(value, label) {
|
|
@@ -2593,6 +2696,59 @@ async function runWhoami(_input, deps) {
|
|
|
2593
2696
|
return { exitCode: 0 };
|
|
2594
2697
|
}
|
|
2595
2698
|
|
|
2699
|
+
// src/commands/workspace.ts
|
|
2700
|
+
async function runWorkspaceList(_input, deps) {
|
|
2701
|
+
try {
|
|
2702
|
+
await requireCredential({
|
|
2703
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
2704
|
+
env: deps.env,
|
|
2705
|
+
store: deps.store
|
|
2706
|
+
});
|
|
2707
|
+
} catch {
|
|
2708
|
+
return writeAuthError(deps);
|
|
2709
|
+
}
|
|
2710
|
+
const result = await deps.client.workspaces.list();
|
|
2711
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
2712
|
+
const raw = unwrapListData(result.data);
|
|
2713
|
+
const items = Array.isArray(raw) ? raw : [];
|
|
2714
|
+
if (deps.outputMode === "human") {
|
|
2715
|
+
if (items.length === 0) {
|
|
2716
|
+
writeEmpty(deps, "No workspaces found.", { ok: true, workspaces: [] });
|
|
2717
|
+
} else {
|
|
2718
|
+
for (const ws of items) {
|
|
2719
|
+
const active = ws.isActive ? "* " : " ";
|
|
2720
|
+
deps.stdout(
|
|
2721
|
+
`${active}${ws.slug} ${ws.name} (${ws.kind}, ${ws.role}, ${ws.plan})
|
|
2722
|
+
`
|
|
2723
|
+
);
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
} else {
|
|
2727
|
+
writeJson(deps, { ok: true, workspaces: items });
|
|
2728
|
+
}
|
|
2729
|
+
return { exitCode: 0 };
|
|
2730
|
+
}
|
|
2731
|
+
async function runWorkspaceUse(slugOrId, _input, deps) {
|
|
2732
|
+
try {
|
|
2733
|
+
await requireCredential({
|
|
2734
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
2735
|
+
env: deps.env,
|
|
2736
|
+
store: deps.store
|
|
2737
|
+
});
|
|
2738
|
+
} catch {
|
|
2739
|
+
return writeAuthError(deps);
|
|
2740
|
+
}
|
|
2741
|
+
const result = await deps.client.workspaces.use(slugOrId);
|
|
2742
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
2743
|
+
const ws = result.data;
|
|
2744
|
+
writeHumanOrJson(
|
|
2745
|
+
deps,
|
|
2746
|
+
success(`Now using workspace: ${ws.name} (${ws.slug})`),
|
|
2747
|
+
{ ok: true, workspace: ws }
|
|
2748
|
+
);
|
|
2749
|
+
return { exitCode: 0 };
|
|
2750
|
+
}
|
|
2751
|
+
|
|
2596
2752
|
// src/context.ts
|
|
2597
2753
|
var import_node2 = require("@dropthis/node");
|
|
2598
2754
|
function createContext(input) {
|
|
@@ -2801,7 +2957,7 @@ function buildProgram(options = {}) {
|
|
|
2801
2957
|
` ${import_picocolors6.default.cyan("dropthis login")}`,
|
|
2802
2958
|
` ${import_picocolors6.default.cyan("dropthis publish ./dist")}`
|
|
2803
2959
|
].join("\n")
|
|
2804
|
-
).version(
|
|
2960
|
+
).version(CLI_VERSION).configureHelp({
|
|
2805
2961
|
subcommandTerm(cmd) {
|
|
2806
2962
|
const args = cmd.registeredArguments.map((a) => {
|
|
2807
2963
|
const name = a.name();
|
|
@@ -2855,6 +3011,9 @@ ${lines.map((l) => ` ${l}`).join("\n")}
|
|
|
2855
3011
|
).option(
|
|
2856
3012
|
"--manifest <file>",
|
|
2857
3013
|
"Publish a multi-file bundle defined in a JSON file (path, content/source_url/content_base64 per file). Cannot combine with a positional input."
|
|
3014
|
+
).option(
|
|
3015
|
+
"--workspace <slugOrId>",
|
|
3016
|
+
"Target workspace slug or id for this publish (delegated keys only; overrides server-side active workspace for this call)"
|
|
2858
3017
|
).option("--url", "Print only the published URL (no JSON envelope)").option(
|
|
2859
3018
|
"--dry-run",
|
|
2860
3019
|
"Show what would be published without publishing (JSON; cannot combine with --url)"
|
|
@@ -3276,6 +3435,47 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3276
3435
|
process.exitCode = result.exitCode;
|
|
3277
3436
|
}
|
|
3278
3437
|
);
|
|
3438
|
+
const workspace = program.command("workspace").description(
|
|
3439
|
+
"Manage workspaces. Switch your active workspace (delegated keys only) or list all workspaces you belong to."
|
|
3440
|
+
);
|
|
3441
|
+
workspace.command("list", { isDefault: true }).description("List workspaces you belong to").option("--json", "Force JSON output").action(async (commandOptions) => {
|
|
3442
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
3443
|
+
const result = await runWorkspaceList(commandOptions, deps);
|
|
3444
|
+
process.exitCode = result.exitCode;
|
|
3445
|
+
});
|
|
3446
|
+
workspace.command("use <slugOrId>").description(
|
|
3447
|
+
"Switch your active workspace (server-side, persists on the credential). Delegated keys only \u2014 pinned service keys cannot switch."
|
|
3448
|
+
).option("--json", "Force JSON output").action(async (slugOrId, commandOptions) => {
|
|
3449
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
3450
|
+
const result = await runWorkspaceUse(slugOrId, commandOptions, deps);
|
|
3451
|
+
process.exitCode = result.exitCode;
|
|
3452
|
+
});
|
|
3453
|
+
const keys = program.command("keys").description(
|
|
3454
|
+
"Mint API keys (delegated login keys or pinned CI service keys)"
|
|
3455
|
+
);
|
|
3456
|
+
keys.command("create").description(
|
|
3457
|
+
"Create an API key. Without --service, mints a delegated account-scoped key (default for login). With --service --workspace <ws>, mints a CI key pinned to that workspace."
|
|
3458
|
+
).option("--label <label>", "Key label").option(
|
|
3459
|
+
"--service",
|
|
3460
|
+
"Mint a pinned service key for CI/automation (requires --workspace to pin it)"
|
|
3461
|
+
).option(
|
|
3462
|
+
"--workspace <slugOrId>",
|
|
3463
|
+
"Pin this service key to the given workspace slug or id (only valid with --service)"
|
|
3464
|
+
).option("--json", "Force JSON output").action(
|
|
3465
|
+
async (commandOptions) => {
|
|
3466
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
3467
|
+
const result = await runKeysCreate(
|
|
3468
|
+
{
|
|
3469
|
+
...commandOptions.label !== void 0 ? { label: commandOptions.label } : {},
|
|
3470
|
+
type: commandOptions.service ? "service" : "delegated",
|
|
3471
|
+
...commandOptions.workspace !== void 0 ? { workspace: commandOptions.workspace } : {},
|
|
3472
|
+
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
3473
|
+
},
|
|
3474
|
+
deps
|
|
3475
|
+
);
|
|
3476
|
+
process.exitCode = result.exitCode;
|
|
3477
|
+
}
|
|
3478
|
+
);
|
|
3279
3479
|
program.command("login").description("Authenticate with email OTP").option("--email <email>", "Email address").option("--otp <otp>", "One-time passcode").option("--json", "Force JSON output").action(
|
|
3280
3480
|
async (commandOptions) => {
|
|
3281
3481
|
if (!commandOptions.email || !commandOptions.otp) {
|
|
@@ -3403,7 +3603,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3403
3603
|
);
|
|
3404
3604
|
const result = await runUpgrade(commandOptions, {
|
|
3405
3605
|
...deps,
|
|
3406
|
-
currentVersion:
|
|
3606
|
+
currentVersion: CLI_VERSION
|
|
3407
3607
|
});
|
|
3408
3608
|
process.exitCode = result.exitCode;
|
|
3409
3609
|
});
|
|
@@ -3514,6 +3714,7 @@ function toDropOptions(options) {
|
|
|
3514
3714
|
...options.shared ? { shared: true } : {},
|
|
3515
3715
|
...options.slug ? { slug: options.slug } : {},
|
|
3516
3716
|
...options.manifest ? { manifest: options.manifest } : {},
|
|
3717
|
+
...options.workspace ? { workspace: options.workspace } : {},
|
|
3517
3718
|
...options.json !== void 0 ? { json: options.json } : {},
|
|
3518
3719
|
...options.quiet !== void 0 ? { quiet: options.quiet } : {},
|
|
3519
3720
|
...options.url !== void 0 ? { url: options.url } : {},
|
|
@@ -3657,7 +3858,7 @@ var showNotice = shouldShowNotice({
|
|
|
3657
3858
|
if (showNotice) {
|
|
3658
3859
|
const notice = noticeFromCache({
|
|
3659
3860
|
cache: updateCache,
|
|
3660
|
-
currentVersion:
|
|
3861
|
+
currentVersion: CLI_VERSION
|
|
3661
3862
|
});
|
|
3662
3863
|
if (notice) {
|
|
3663
3864
|
process.stderr.write(`
|