wawesome 0.13.0 → 0.14.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 +44 -5
- package/dist/index.mjs +134 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,7 +121,9 @@ npx wawesome deploy
|
|
|
121
121
|
| `npx wawesome domains detach <host>` | Stop serving the app at a domain you attached |
|
|
122
122
|
| `npx wawesome credentials` | List deploy credentials: name, prefix, capabilities, Apps, last use |
|
|
123
123
|
| `npx wawesome credentials mint <name>` | Mint a deploy credential and print its secret, once |
|
|
124
|
+
| `npx wawesome credentials regenerate <name>`| Replace a deploy credential's secret, keeping its name |
|
|
124
125
|
| `npx wawesome credentials revoke <name>`| Revoke a deploy credential by name or prefix |
|
|
126
|
+
| `npx wawesome credentials delete <name>`| Delete a revoked or expired credential, freeing its name |
|
|
125
127
|
|
|
126
128
|
---
|
|
127
129
|
|
|
@@ -292,9 +294,9 @@ keyboard to log in. It belongs to the workspace rather than to you: it keeps wor
|
|
|
292
294
|
and revoking it does not end your own session. Once you have one, [Deploying from CI](#deploying-from-ci)
|
|
293
295
|
is what to do with it.
|
|
294
296
|
|
|
295
|
-
Minting, listing
|
|
296
|
-
themselves, whatever those carry, so a leaked credential cannot mint another
|
|
297
|
-
ordinary `npx wawesome login` session.
|
|
297
|
+
Minting, listing, regenerating, revoking and deleting belong to the workspace owner. They are closed
|
|
298
|
+
to deploy credentials themselves, whatever those carry, so a leaked credential cannot mint another or
|
|
299
|
+
renew its own expiry. All five run on your ordinary `npx wawesome login` session.
|
|
298
300
|
|
|
299
301
|
### Mint one
|
|
300
302
|
|
|
@@ -342,6 +344,27 @@ Name, displayable prefix, capabilities, Apps, last use and expiry. Never the sec
|
|
|
342
344
|
platform no longer holds. `LAST USED` lags by a few minutes and reads `never` for a credential
|
|
343
345
|
nothing has ever presented, which is a better reason to revoke one than any calendar date.
|
|
344
346
|
|
|
347
|
+
### Rotate one
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
npx wawesome credentials regenerate ci-pipeline
|
|
351
|
+
npx wawesome credentials regenerate ci --expires never --yes
|
|
352
|
+
npx wawesome credentials regenerate ci-pipeline > secret.txt
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Regenerating replaces the secret where it stands. The credential keeps its id, its name, its
|
|
356
|
+
capabilities and the Apps it may reach, so the only thing to change in your CI settings is the secret
|
|
357
|
+
itself. Its displayable prefix changes with it, since the prefix is what you match one against. The
|
|
358
|
+
new secret is printed once, on stdout alone, exactly as at minting.
|
|
359
|
+
|
|
360
|
+
It asks first, because anything holding the old secret stops working the moment this lands and has to
|
|
361
|
+
be given the new one; `--yes` is the answer where nobody is at the keyboard. Without `--expires` the
|
|
362
|
+
new secret lives ninety days, the same rule minting follows, including on a credential that never
|
|
363
|
+
expired.
|
|
364
|
+
|
|
365
|
+
An expired credential regenerates into a working one — that is the ordinary reason to reach for this.
|
|
366
|
+
A revoked one is refused, because nothing un-revokes a credential.
|
|
367
|
+
|
|
345
368
|
### Revoke one
|
|
346
369
|
|
|
347
370
|
```bash
|
|
@@ -354,6 +377,22 @@ where nobody is at the keyboard, and a prefix naming more than one credential is
|
|
|
354
377
|
guessed at. A revocation lands on the very next request presenting the secret, and nothing un-revokes
|
|
355
378
|
it.
|
|
356
379
|
|
|
380
|
+
### Delete one
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
npx wawesome credentials delete ci-pipeline
|
|
384
|
+
npx wawesome credentials delete wawe_ab3k9x --yes
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Deleting is a second act, not a shortcut through revoking, so only a credential that has already
|
|
388
|
+
stopped working can be deleted. Revoke a live one first. It resolves its target the way revoking
|
|
389
|
+
does, by name or by displayable prefix, and asks before it does it unless you pass `--yes`.
|
|
390
|
+
|
|
391
|
+
What deleting gives up is the reason revoking left the record behind. The credential leaves the
|
|
392
|
+
listing, the name comes free to mint again, and a pipeline still presenting the secret is told the
|
|
393
|
+
secret is unknown rather than that somebody revoked it. Whoever is debugging that pipeline goes
|
|
394
|
+
looking in their CI settings instead of your dashboard.
|
|
395
|
+
|
|
357
396
|
---
|
|
358
397
|
|
|
359
398
|
## Configuration and a custom gateway
|
|
@@ -666,8 +705,8 @@ While it is set:
|
|
|
666
705
|
- a refusal names which of four things happened: the credential is unknown, revoked, expired, or does not carry what
|
|
667
706
|
the command needs. It does not ask you to sign in again, which a pipeline cannot do;
|
|
668
707
|
- `login` and `logout` refuse, because neither would change what the next command authenticates as;
|
|
669
|
-
- `credentials` is refused by the platform, because minting, listing
|
|
670
|
-
credentials whatever they carry;
|
|
708
|
+
- `credentials` is refused by the platform, because minting, listing, regenerating, revoking and
|
|
709
|
+
deleting are closed to credentials whatever they carry;
|
|
671
710
|
- `whoami` names the credential by its prefix, so you can match it against the one in your CI settings.
|
|
672
711
|
|
|
673
712
|
---
|
package/dist/index.mjs
CHANGED
|
@@ -883,7 +883,7 @@ async function buildJs(entryInput, options) {
|
|
|
883
883
|
* that has to name this version — `--version`, the dependency a scaffolded
|
|
884
884
|
* project pins — reads it here, so a release bumps one file.
|
|
885
885
|
*/
|
|
886
|
-
const CLI_VERSION = "0.
|
|
886
|
+
const CLI_VERSION = "0.14.0";
|
|
887
887
|
//#endregion
|
|
888
888
|
//#region src/prompt.ts
|
|
889
889
|
/**
|
|
@@ -4669,6 +4669,7 @@ async function workspaceCommand(action, target, options) {
|
|
|
4669
4669
|
//#endregion
|
|
4670
4670
|
//#region src/deploy-credentials.ts
|
|
4671
4671
|
const SECRET_SHOWN_ONCE = "Copy it now. This is the only time it will be shown. If you lose it, revoke this credential and mint another.";
|
|
4672
|
+
const REGENERATED_SECRET_SHOWN_ONCE = "Copy it now. This is the only time it will be shown. If you lose it, regenerate this credential again.";
|
|
4672
4673
|
function requireCredentials$1() {
|
|
4673
4674
|
const creds = readCredentials();
|
|
4674
4675
|
if (!creds) {
|
|
@@ -4750,6 +4751,18 @@ async function fetchCredentials(creds) {
|
|
|
4750
4751
|
if (!res.ok) throw await refusal(res, `Failed to read the credentials (HTTP ${res.status}).`);
|
|
4751
4752
|
return (await res.json()).credentials ?? [];
|
|
4752
4753
|
}
|
|
4754
|
+
async function regenerateCredential(creds, credentialId, payload) {
|
|
4755
|
+
const res = await authorizedFetch(`${creds.gateway_url}/v1/tenant/credentials/${encodeURIComponent(credentialId)}/regenerate`, {
|
|
4756
|
+
method: "POST",
|
|
4757
|
+
headers: {
|
|
4758
|
+
Authorization: `Bearer ${creds.tenant_jwt}`,
|
|
4759
|
+
"Content-Type": "application/json"
|
|
4760
|
+
},
|
|
4761
|
+
body: JSON.stringify(payload)
|
|
4762
|
+
});
|
|
4763
|
+
if (!res.ok) throw await refusal(res, `Failed to regenerate the credential (HTTP ${res.status}).`);
|
|
4764
|
+
return await res.json();
|
|
4765
|
+
}
|
|
4753
4766
|
async function revokeCredential(creds, credentialId) {
|
|
4754
4767
|
const res = await authorizedFetch(`${creds.gateway_url}/v1/tenant/credentials/${encodeURIComponent(credentialId)}/revoke`, {
|
|
4755
4768
|
method: "POST",
|
|
@@ -4758,6 +4771,13 @@ async function revokeCredential(creds, credentialId) {
|
|
|
4758
4771
|
if (!res.ok) throw await refusal(res, `Failed to revoke the credential (HTTP ${res.status}).`);
|
|
4759
4772
|
return await res.json();
|
|
4760
4773
|
}
|
|
4774
|
+
async function deleteCredential(creds, credentialId) {
|
|
4775
|
+
const res = await authorizedFetch(`${creds.gateway_url}/v1/tenant/credentials/${encodeURIComponent(credentialId)}`, {
|
|
4776
|
+
method: "DELETE",
|
|
4777
|
+
headers: { Authorization: `Bearer ${creds.tenant_jwt}` }
|
|
4778
|
+
});
|
|
4779
|
+
if (!res.ok) throw await refusal(res, `Failed to delete the credential (HTTP ${res.status}).`);
|
|
4780
|
+
}
|
|
4761
4781
|
/**
|
|
4762
4782
|
* Mint one credential.
|
|
4763
4783
|
*
|
|
@@ -4785,12 +4805,22 @@ async function mintCredentialCommand(name, options) {
|
|
|
4785
4805
|
} catch (err) {
|
|
4786
4806
|
fail(errorText(err));
|
|
4787
4807
|
}
|
|
4788
|
-
|
|
4808
|
+
reveal(`Minted deploy credential '${credential.name}'.`, credential, SECRET_SHOWN_ONCE);
|
|
4809
|
+
}
|
|
4810
|
+
/**
|
|
4811
|
+
* Hand the secret over, once.
|
|
4812
|
+
*
|
|
4813
|
+
* The secret goes to stdout on a line of its own and everything a person reads
|
|
4814
|
+
* goes to stderr, so `wawesome credentials mint ci > secret` writes the secret
|
|
4815
|
+
* and not one character besides.
|
|
4816
|
+
*/
|
|
4817
|
+
function reveal(headline, credential, shownOnce) {
|
|
4818
|
+
console.error(`\n[wawesome] ✔ ${headline}\n`);
|
|
4789
4819
|
console.error(` Prefix: ${credential.prefix}`);
|
|
4790
4820
|
console.error(` Capabilities: ${credential.capabilities.join(", ")}`);
|
|
4791
4821
|
console.error(` Apps: ${namedApps(credential.apps) ?? "every App in the workspace"}`);
|
|
4792
4822
|
console.error(` Expires: ${asUtc(credential.expires_at)}`);
|
|
4793
|
-
console.error(`\n ${
|
|
4823
|
+
console.error(`\n ${shownOnce}\n`);
|
|
4794
4824
|
console.log(credential.secret);
|
|
4795
4825
|
console.error("");
|
|
4796
4826
|
}
|
|
@@ -4876,9 +4906,8 @@ function matchCredentials(credentials, target) {
|
|
|
4876
4906
|
const wanted = typed.startsWith("wawe_") ? credentialPrefix(typed) : typed;
|
|
4877
4907
|
return credentials.filter((credential) => credential.prefix.startsWith(wanted));
|
|
4878
4908
|
}
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
const creds = requireCredentials$1();
|
|
4909
|
+
/** The one credential a typed name or prefix means, or an exit saying why none. */
|
|
4910
|
+
async function resolveCredential(creds, target, options) {
|
|
4882
4911
|
if (options.verbose) console.error(`[wawesome:verbose] GET ${creds.gateway_url}/v1/tenant/credentials`);
|
|
4883
4912
|
let credentials;
|
|
4884
4913
|
try {
|
|
@@ -4889,7 +4918,57 @@ async function revokeCredentialCommand(target, options) {
|
|
|
4889
4918
|
const matched = matchCredentials(credentials, target);
|
|
4890
4919
|
if (matched.length === 0) fail(`No deploy credential named or prefixed '${asShown(target)}' in this workspace.`, "Run 'wawesome credentials list' to see what this workspace has.");
|
|
4891
4920
|
if (matched.length > 1) fail(`'${asShown(target)}' names more than one credential:`, ...matched.map((credential) => ` ${credential.name} (${credential.prefix})`), "Name one of them, or give more of its prefix.");
|
|
4892
|
-
|
|
4921
|
+
return matched[0];
|
|
4922
|
+
}
|
|
4923
|
+
/**
|
|
4924
|
+
* Replace a credential's secret where it stands, keeping the name a pipeline's
|
|
4925
|
+
* settings already refer to.
|
|
4926
|
+
*
|
|
4927
|
+
* Confirmed like a revoke, because it is one for whatever holds the old secret:
|
|
4928
|
+
* the pipeline stops on its very next request until somebody gives it the new
|
|
4929
|
+
* one.
|
|
4930
|
+
*/
|
|
4931
|
+
async function regenerateCredentialCommand(target, options) {
|
|
4932
|
+
if (!target || !target.trim()) fail("No credential given. Usage: wawesome credentials regenerate <name-or-prefix>");
|
|
4933
|
+
const creds = requireCredentials$1();
|
|
4934
|
+
const credential = await resolveCredential(creds, target, options);
|
|
4935
|
+
if (credential.revoked_at) fail(`'${credential.name}' (${credential.prefix}) was revoked at ${asUtc(credential.revoked_at)}, and nothing un-revokes one.`, `Mint a replacement, or delete this one first to free its name for it.`);
|
|
4936
|
+
const payload = {};
|
|
4937
|
+
const expiry = parseExpiry(options.expires);
|
|
4938
|
+
if (expiry !== void 0) payload.expiry = expiry;
|
|
4939
|
+
if (!options.yes) {
|
|
4940
|
+
if (!isInteractive()) fail(`Regenerating asks for confirmation, and there is nobody to ask.`, `Pass --yes to regenerate '${credential.name}' (${credential.prefix}) without being asked.`);
|
|
4941
|
+
let confirmed;
|
|
4942
|
+
try {
|
|
4943
|
+
confirmed = await confirm({
|
|
4944
|
+
message: `Regenerate '${credential.name}' (${credential.prefix})? Anything holding the old secret stops working at once and has to be given the new one.`,
|
|
4945
|
+
default: false
|
|
4946
|
+
});
|
|
4947
|
+
} catch {
|
|
4948
|
+
confirmed = false;
|
|
4949
|
+
}
|
|
4950
|
+
if (!confirmed) {
|
|
4951
|
+
console.error(`[wawesome] Cancelled. '${credential.name}' still works.`);
|
|
4952
|
+
return;
|
|
4953
|
+
}
|
|
4954
|
+
}
|
|
4955
|
+
if (options.verbose) {
|
|
4956
|
+
console.error(`[wawesome:verbose] POST ${creds.gateway_url}/v1/tenant/credentials/${credential.id}/regenerate`);
|
|
4957
|
+
console.error(`[wawesome:verbose] Payload: ${JSON.stringify(payload)}`);
|
|
4958
|
+
}
|
|
4959
|
+
let regenerated;
|
|
4960
|
+
try {
|
|
4961
|
+
regenerated = await regenerateCredential(creds, credential.id, payload);
|
|
4962
|
+
} catch (err) {
|
|
4963
|
+
if (err instanceof GatewayError && err.status === 404) fail(`'${credential.name}' (${credential.prefix}) no longer exists in this workspace.`);
|
|
4964
|
+
fail(errorText(err));
|
|
4965
|
+
}
|
|
4966
|
+
reveal(`Regenerated '${regenerated.name}'. Anything still presenting the old secret is refused from its very next request.`, regenerated, REGENERATED_SECRET_SHOWN_ONCE);
|
|
4967
|
+
}
|
|
4968
|
+
async function revokeCredentialCommand(target, options) {
|
|
4969
|
+
if (!target || !target.trim()) fail("No credential given. Usage: wawesome credentials revoke <name-or-prefix>");
|
|
4970
|
+
const creds = requireCredentials$1();
|
|
4971
|
+
const credential = await resolveCredential(creds, target, options);
|
|
4893
4972
|
if (credential.revoked_at) {
|
|
4894
4973
|
console.log(`[wawesome] '${credential.name}' (${credential.prefix}) was already revoked at ${asUtc(credential.revoked_at)}. Nothing to do.`);
|
|
4895
4974
|
return;
|
|
@@ -4921,11 +5000,49 @@ async function revokeCredentialCommand(target, options) {
|
|
|
4921
5000
|
console.log(`\n[wawesome] ✔ Revoked '${revoked.name}' (${revoked.prefix}).`);
|
|
4922
5001
|
console.log("[wawesome] Anything still presenting it is refused from its very next request.\n");
|
|
4923
5002
|
}
|
|
5003
|
+
async function deleteCredentialCommand(target, options) {
|
|
5004
|
+
if (!target || !target.trim()) fail("No credential given. Usage: wawesome credentials delete <name-or-prefix>");
|
|
5005
|
+
const creds = requireCredentials$1();
|
|
5006
|
+
const credential = await resolveCredential(creds, target, options);
|
|
5007
|
+
const named = `'${credential.name}' (${credential.prefix})`;
|
|
5008
|
+
if (statusOf(credential, Date.now()) === "active") fail(`${named} still works, and only a credential that has stopped working is deleted.`, `Revoke it first: wawesome credentials revoke ${credential.name}`);
|
|
5009
|
+
if (!options.yes) {
|
|
5010
|
+
if (!isInteractive()) fail("Deleting asks for confirmation, and there is nobody to ask.", `Pass --yes to delete ${named} without being asked.`);
|
|
5011
|
+
console.log(`\n[wawesome] Deleting ${named} forgets it.`);
|
|
5012
|
+
console.log(`[wawesome] It leaves the listing, and the name '${credential.name}' comes free.`);
|
|
5013
|
+
console.log("[wawesome] Anything still presenting its secret is told the secret is unknown, rather");
|
|
5014
|
+
console.log("[wawesome] than that somebody here revoked it.\n");
|
|
5015
|
+
let confirmed;
|
|
5016
|
+
try {
|
|
5017
|
+
confirmed = await confirm({
|
|
5018
|
+
message: `Delete ${named}?`,
|
|
5019
|
+
default: false
|
|
5020
|
+
});
|
|
5021
|
+
} catch {
|
|
5022
|
+
confirmed = false;
|
|
5023
|
+
}
|
|
5024
|
+
if (!confirmed) {
|
|
5025
|
+
console.log(`[wawesome] Cancelled. ${named} is still listed.`);
|
|
5026
|
+
return;
|
|
5027
|
+
}
|
|
5028
|
+
}
|
|
5029
|
+
if (options.verbose) console.error(`[wawesome:verbose] DELETE ${creds.gateway_url}/v1/tenant/credentials/${credential.id}`);
|
|
5030
|
+
try {
|
|
5031
|
+
await deleteCredential(creds, credential.id);
|
|
5032
|
+
} catch (err) {
|
|
5033
|
+
if (err instanceof GatewayError && err.status === 404) fail(`${named} no longer exists in this workspace.`);
|
|
5034
|
+
fail(errorText(err));
|
|
5035
|
+
}
|
|
5036
|
+
console.log(`\n[wawesome] ✔ Deleted ${named}. The name '${credential.name}' is free again.`);
|
|
5037
|
+
console.log("[wawesome] Anything still presenting its secret is told the secret is unknown.\n");
|
|
5038
|
+
}
|
|
4924
5039
|
async function credentialsCommand(action, target, options) {
|
|
4925
5040
|
if (!action || action === "list" || action === "ls") return listCredentialsCommand(options);
|
|
4926
5041
|
if (action === "mint") return mintCredentialCommand(target, options);
|
|
5042
|
+
if (action === "regenerate") return regenerateCredentialCommand(target, options);
|
|
4927
5043
|
if (action === "revoke") return revokeCredentialCommand(target, options);
|
|
4928
|
-
|
|
5044
|
+
if (action === "delete") return deleteCredentialCommand(target, options);
|
|
5045
|
+
fail(`Unknown credentials action '${action}'.`, "Usage: wawesome credentials [list|mint <name>|regenerate <name-or-prefix>|revoke <name-or-prefix>|delete <name-or-prefix>]");
|
|
4929
5046
|
}
|
|
4930
5047
|
//#endregion
|
|
4931
5048
|
//#region src/cron.ts
|
|
@@ -5386,7 +5503,7 @@ cli.command("logout", "Clear stored authentication credentials").action(() => lo
|
|
|
5386
5503
|
cli.command("whoami", "Show current login session info").action(() => whoami());
|
|
5387
5504
|
cli.command("workspace [action] [name]", "Show the workspace, or rename its public address").usage("workspace <action> [name]\n\nActions:\n show Show the workspace name, address, and whether it can still change\n rename <name> Change the public address, while nothing live depends on it").example("wawesome workspace").example("wawesome workspace rename northwind").option("-v, --verbose", "Enable verbose debug output").action((action, name, options) => workspaceCommand(action, name, options));
|
|
5388
5505
|
cli.command("templates [action]", "Browse the template catalog").usage("templates [action]\n\nActions:\n list (ls) Show every available template (default)").example("wawesome templates").example("wawesome templates list").option("--api <url>", "API URL (default: https://api.wawesome.io)").option("-v, --verbose", "Enable verbose debug output").action((action, options) => templatesCommand(action, options));
|
|
5389
|
-
cli.command("credentials [action] [target]", "Mint, list
|
|
5506
|
+
cli.command("credentials [action] [target]", "Mint, list, regenerate, revoke and delete deploy credentials").alias("credential").usage(`credentials <action> [options]
|
|
5390
5507
|
|
|
5391
5508
|
A deploy credential is what a CI pipeline or an agent authenticates with, where
|
|
5392
5509
|
there is nobody at a keyboard to log in. Minting is the only time the secret is
|
|
@@ -5395,7 +5512,9 @@ cli.command("credentials [action] [target]", "Mint, list and revoke deploy crede
|
|
|
5395
5512
|
Actions:
|
|
5396
5513
|
list (ls) Show every credential: name, prefix, capabilities, Apps, last use, expiry (default)
|
|
5397
5514
|
mint <name> Mint one, printing the secret exactly once
|
|
5515
|
+
regenerate <name-or-prefix> Replace one's secret, keeping its name, capabilities and Apps
|
|
5398
5516
|
revoke <name-or-prefix> Revoke one, immediately and for good
|
|
5517
|
+
delete <name-or-prefix> Forget a revoked or expired one, freeing its name
|
|
5399
5518
|
|
|
5400
5519
|
Examples:
|
|
5401
5520
|
wawesome credentials
|
|
@@ -5404,11 +5523,16 @@ cli.command("credentials [action] [target]", "Mint, list and revoke deploy crede
|
|
|
5404
5523
|
wawesome credentials mint prod-deploy -c deploy -a prod --expires 30
|
|
5405
5524
|
wawesome credentials mint ci -c deploy,domains:attach -a prod
|
|
5406
5525
|
wawesome credentials mint ci-pipeline > /tmp/secret
|
|
5526
|
+
wawesome credentials regenerate ci-pipeline
|
|
5527
|
+
wawesome credentials regenerate ci --expires never --yes
|
|
5407
5528
|
wawesome credentials revoke ci-pipeline
|
|
5408
|
-
wawesome credentials revoke wawe_ab3k9x --yes
|
|
5529
|
+
wawesome credentials revoke wawe_ab3k9x --yes
|
|
5530
|
+
wawesome credentials delete ci-pipeline`).option("-c, --capability <capability>", "Capability to grant: deploy, logs:read, domains:attach (repeatable or comma-separated, default: deploy)").option("-a, --app <app>", "Restrict the credential to this App (repeatable or comma-separated, default: every App)").option("--expires <days|never>", "Days until the credential expires, or 'never' (default: 90)").option("-y, --yes", "Skip the confirmation a regenerate, revoke or delete asks for").option("-v, --verbose", "Enable verbose debug output").action((action, target, options) => credentialsCommand(action, target, options));
|
|
5409
5531
|
cli.command("credentials mint <name>", "Mint a deploy credential, printing its secret exactly once").option("-c, --capability <capability>", "Capability to grant: deploy, logs:read, domains:attach (repeatable or comma-separated)").option("-a, --app <app>", "Restrict the credential to this App (repeatable or comma-separated)").option("--expires <days|never>", "Days until the credential expires, or 'never' (default: 90)").option("-v, --verbose", "Enable verbose debug output").action((name, options) => mintCredentialCommand(name, options));
|
|
5410
5532
|
cli.command("credentials list", "List deploy credentials, never their secrets").alias("credentials ls").option("-v, --verbose", "Enable verbose debug output").action((options) => listCredentialsCommand(options));
|
|
5533
|
+
cli.command("credentials regenerate <name-or-prefix>", "Replace a deploy credential's secret, keeping its name, capabilities and Apps").option("--expires <days|never>", "Days until the regenerated credential expires, or 'never' (default: 90)").option("-y, --yes", "Regenerate without being asked to confirm").option("-v, --verbose", "Enable verbose debug output").action((target, options) => regenerateCredentialCommand(target, options));
|
|
5411
5534
|
cli.command("credentials revoke <name-or-prefix>", "Revoke a deploy credential, immediately and for good").option("-y, --yes", "Revoke without being asked to confirm").option("-v, --verbose", "Enable verbose debug output").action((target, options) => revokeCredentialCommand(target, options));
|
|
5535
|
+
cli.command("credentials delete <name-or-prefix>", "Delete a revoked or expired deploy credential, freeing its name").option("-y, --yes", "Delete without being asked to confirm").option("-v, --verbose", "Enable verbose debug output").action((target, options) => deleteCredentialCommand(target, options));
|
|
5412
5536
|
cli.command("init", "Scaffold a new function project in the current directory").usage("init [options]\n\nWith --template, the project is fetched from the template catalog, wired up\nfrom what the template declares it needs, and deployed. Run 'wawesome templates'\nto see what is available.").example("wawesome init").example("wawesome init --template stripe-webhook").option("-t, --template <name>", "Scaffold from a catalog template and deploy it").option("--api <url>", "API URL (default: https://api.wawesome.io)").option("--dashboard <url>", "Dashboard URL (default: https://dashboard.wawesome.io)").option("--no-install", "Skip installing dependencies after scaffolding").option("--root", "Generate a root function router template").option("-v, --verbose", "Enable verbose debug output").action((options) => init(options));
|
|
5413
5537
|
cli.command("logs [function-name-or-invocation-id]", "View invocation history, fetch log output, or follow live").usage(`logs [target] [options]
|
|
5414
5538
|
|