wawesome 0.0.8 → 0.0.10
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 +22 -0
- package/dist/index.mjs +163 -51
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -67,6 +67,13 @@ dlx`, `bun x`), so the types are there when you open the project and the bundler
|
|
|
67
67
|
template's imports. Pass `--no-install` to do it yourself. A failed install never stops the flow;
|
|
68
68
|
the command to re-run is printed.
|
|
69
69
|
|
|
70
|
+
Before any of that is sent anywhere, the CLI shows you the **public URL your Function will have**
|
|
71
|
+
and offers to change your workspace address — the part of that URL that is yours rather than this
|
|
72
|
+
project's, and the same one `wawesome workspace show` prints. It is randomly minted at signup and
|
|
73
|
+
stays changeable until your first deploy, at which point it locks for good, because live URLs carry
|
|
74
|
+
it. Press enter to keep it. If it is already locked, the offer is not made and the reason is said
|
|
75
|
+
plainly.
|
|
76
|
+
|
|
70
77
|
Being logged in is checked **before** the first question, not at the deploy: an expired session
|
|
71
78
|
offers you a login there and then, and declining still leaves you the project plus the two commands
|
|
72
79
|
that finish it.
|
|
@@ -193,6 +200,21 @@ Every project directory includes a `wawesome-function.json` file generated durin
|
|
|
193
200
|
`app` is the App this Function is deployed into, and it is client-facing — every deploy from this
|
|
194
201
|
directory is scoped to it.
|
|
195
202
|
|
|
203
|
+
### Reserved headers
|
|
204
|
+
|
|
205
|
+
`x-wawesome-*` belongs to the platform in both directions. It is stripped off the request before your
|
|
206
|
+
handler sees it, and off your response before the caller does — so **do not name a header of your own
|
|
207
|
+
on that prefix**: it is dropped silently rather than rejected, and you will not get an error telling
|
|
208
|
+
you why it vanished.
|
|
209
|
+
|
|
210
|
+
Three headers arrive or leave on it, and the stripping is what makes them worth trusting:
|
|
211
|
+
|
|
212
|
+
| Header | Direction | What it means |
|
|
213
|
+
| --- | --- | --- |
|
|
214
|
+
| `x-wawesome-forwarded-prefix` | inbound | The mount that was stripped from the path. Join it to the path you observe to rebuild the caller's URL. |
|
|
215
|
+
| `x-wawesome-invocation-id` | outbound | The id of this run — the key to fetch its logs with `npx wawesome logs --invocation <id>`. |
|
|
216
|
+
| `x-wawesome-error` | outbound | Present only when the platform failed, never when your Function did. Its *absence* means the status on the wire is yours. |
|
|
217
|
+
|
|
196
218
|
### Local Development / Gateway Overrides
|
|
197
219
|
|
|
198
220
|
If you are running a local gateway or self-hosted instance, you can configure your CLI Gateway URL using any of the
|
package/dist/index.mjs
CHANGED
|
@@ -161,7 +161,7 @@ async function buildJs(entryInput, options) {
|
|
|
161
161
|
* that has to name this version — `--version`, the dependency a scaffolded
|
|
162
162
|
* project pins — reads it here, so a release bumps one file.
|
|
163
163
|
*/
|
|
164
|
-
const CLI_VERSION = "0.0.
|
|
164
|
+
const CLI_VERSION = "0.0.10";
|
|
165
165
|
//#endregion
|
|
166
166
|
//#region src/prompt.ts
|
|
167
167
|
/**
|
|
@@ -284,6 +284,34 @@ async function resolveWorkspace(creds) {
|
|
|
284
284
|
};
|
|
285
285
|
}
|
|
286
286
|
/**
|
|
287
|
+
* What a refused rename means for whoever asked for it.
|
|
288
|
+
*
|
|
289
|
+
* Shared by the two places that offer a rename, so they cannot drift into
|
|
290
|
+
* telling a user different things about the same reason — and `retryable` is
|
|
291
|
+
* what separates a name worth retyping from one that no name would fix.
|
|
292
|
+
*/
|
|
293
|
+
function renameAdvice(reason) {
|
|
294
|
+
switch (reason) {
|
|
295
|
+
case "taken":
|
|
296
|
+
case "reserved": return {
|
|
297
|
+
text: "Pick a different name.",
|
|
298
|
+
retryable: true
|
|
299
|
+
};
|
|
300
|
+
case "malformed": return {
|
|
301
|
+
text: "Use lowercase letters, numbers and single hyphens.",
|
|
302
|
+
retryable: true
|
|
303
|
+
};
|
|
304
|
+
case "locked": return {
|
|
305
|
+
text: "A deploy landed while this was running, which fixed the address for good.",
|
|
306
|
+
retryable: false
|
|
307
|
+
};
|
|
308
|
+
default: return {
|
|
309
|
+
text: "",
|
|
310
|
+
retryable: false
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
287
315
|
* Ask for the workspace's public address to become `slug`.
|
|
288
316
|
*
|
|
289
317
|
* The slug is sent exactly as typed. Sanitizing it the way an App slug is
|
|
@@ -301,17 +329,12 @@ async function renameTenantSlug(creds, slug) {
|
|
|
301
329
|
});
|
|
302
330
|
if (!res.ok) throw await asGatewayError(res, `Rename failed (HTTP ${res.status}).`);
|
|
303
331
|
const result = await res.json();
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
...stored,
|
|
332
|
+
writeCredentials({
|
|
333
|
+
...readCredentials() ?? creds,
|
|
307
334
|
tenant_slug: result.tenant_slug
|
|
308
335
|
});
|
|
309
336
|
return result;
|
|
310
337
|
}
|
|
311
|
-
/** The address a deployed Function answers on, for a workspace and app. */
|
|
312
|
-
function publicInvokeUrl(gatewayUrl, tenantSlug, appSlug, functionName) {
|
|
313
|
-
return `${gatewayUrl}/v1/s/${encodeURIComponent(tenantSlug)}/apps/${encodeURIComponent(appSlug)}/functions/${encodeURIComponent(functionName)}/invoke`;
|
|
314
|
-
}
|
|
315
338
|
//#endregion
|
|
316
339
|
//#region src/auth.ts
|
|
317
340
|
/**
|
|
@@ -521,6 +544,20 @@ async function whoami() {
|
|
|
521
544
|
console.log(` Gateway: ${creds.gateway_url}\n`);
|
|
522
545
|
}
|
|
523
546
|
//#endregion
|
|
547
|
+
//#region ../shared/public-address.ts
|
|
548
|
+
const INVOCATION_PREFIX = "/x";
|
|
549
|
+
const SUBTREE_NOTE = "Every path beneath this address reaches the Function.";
|
|
550
|
+
function mountBase(origin, tenantSlug) {
|
|
551
|
+
return `${origin.replace(/\/+$/, "")}${INVOCATION_PREFIX}/${encodeURIComponent(tenantSlug)}`;
|
|
552
|
+
}
|
|
553
|
+
function publicAddress(origin, tenantSlug, appSlug, functionSlug) {
|
|
554
|
+
return `${mountBase(origin, tenantSlug)}/${encodeURIComponent(appSlug)}/${encodeURIComponent(functionSlug)}`;
|
|
555
|
+
}
|
|
556
|
+
/** The same address with the app and function still to be chosen. */
|
|
557
|
+
function publicAddressTemplate(origin, tenantSlug) {
|
|
558
|
+
return `${mountBase(origin, tenantSlug)}/<app>/<function>`;
|
|
559
|
+
}
|
|
560
|
+
//#endregion
|
|
524
561
|
//#region src/deploy.ts
|
|
525
562
|
/**
|
|
526
563
|
* Deploy a function: build → upload JS to gateway → promote.
|
|
@@ -617,10 +654,10 @@ async function deploy(entryInput, options) {
|
|
|
617
654
|
}
|
|
618
655
|
process.exit(1);
|
|
619
656
|
}
|
|
620
|
-
let
|
|
657
|
+
let address = null;
|
|
621
658
|
try {
|
|
622
659
|
const { slug } = await resolveWorkspace(creds);
|
|
623
|
-
|
|
660
|
+
address = publicAddress(creds.gateway_url, slug, app, funcName);
|
|
624
661
|
} catch (err) {
|
|
625
662
|
if (isVerbose) console.log(`[wawesome:verbose] Could not resolve the workspace address: ${err instanceof Error ? err.message : err}`);
|
|
626
663
|
}
|
|
@@ -630,13 +667,16 @@ async function deploy(entryInput, options) {
|
|
|
630
667
|
console.log(`\n App: ${app}`);
|
|
631
668
|
console.log(` Function: ${funcName}`);
|
|
632
669
|
if (version !== void 0) console.log(` Version: ${version}`);
|
|
633
|
-
if (
|
|
670
|
+
if (address) {
|
|
671
|
+
console.log(`\n URL: \x1b[36m${address}\x1b[0m`);
|
|
672
|
+
console.log(` ${SUBTREE_NOTE}`);
|
|
673
|
+
}
|
|
634
674
|
console.log("======================================================\n");
|
|
635
675
|
return {
|
|
636
676
|
app,
|
|
637
677
|
functionName: funcName,
|
|
638
678
|
version,
|
|
639
|
-
|
|
679
|
+
address
|
|
640
680
|
};
|
|
641
681
|
}
|
|
642
682
|
//#endregion
|
|
@@ -987,11 +1027,9 @@ function alignCliDependency(dir, version) {
|
|
|
987
1027
|
const file = path.join(dir, PACKAGE_FILE);
|
|
988
1028
|
const pkg = readJson(file);
|
|
989
1029
|
const wanted = `^${version}`;
|
|
990
|
-
for (const field of
|
|
1030
|
+
for (const { field, range } of declaredCliRanges(pkg)) {
|
|
1031
|
+
if (range === wanted) continue;
|
|
991
1032
|
const deps = pkg[field];
|
|
992
|
-
if (!isRecord(deps)) continue;
|
|
993
|
-
const current = deps[CLI_PACKAGE];
|
|
994
|
-
if (typeof current !== "string" || current === wanted) continue;
|
|
995
1033
|
writeJson(file, {
|
|
996
1034
|
...pkg,
|
|
997
1035
|
[field]: {
|
|
@@ -1000,12 +1038,22 @@ function alignCliDependency(dir, version) {
|
|
|
1000
1038
|
}
|
|
1001
1039
|
});
|
|
1002
1040
|
return {
|
|
1003
|
-
from:
|
|
1041
|
+
from: range,
|
|
1004
1042
|
to: wanted
|
|
1005
1043
|
};
|
|
1006
1044
|
}
|
|
1007
1045
|
return null;
|
|
1008
1046
|
}
|
|
1047
|
+
/** Where a template declares the CLI, and at which range. */
|
|
1048
|
+
function declaredCliRanges(pkg) {
|
|
1049
|
+
return ["dependencies", "devDependencies"].flatMap((field) => {
|
|
1050
|
+
const deps = pkg[field];
|
|
1051
|
+
return isRecord(deps) && typeof deps[CLI_PACKAGE] === "string" ? [{
|
|
1052
|
+
field,
|
|
1053
|
+
range: deps[CLI_PACKAGE]
|
|
1054
|
+
}] : [];
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1009
1057
|
function isRecord(value) {
|
|
1010
1058
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1011
1059
|
}
|
|
@@ -1039,9 +1087,9 @@ function collidingPaths(dir, relativePaths) {
|
|
|
1039
1087
|
* not be resolved the message still prints, with the placeholder left visible
|
|
1040
1088
|
* rather than a confident "undefined".
|
|
1041
1089
|
*/
|
|
1042
|
-
function renderPostDeploy(postDeploy,
|
|
1043
|
-
if (!
|
|
1044
|
-
return postDeploy.split("{{url}}").join(
|
|
1090
|
+
function renderPostDeploy(postDeploy, address) {
|
|
1091
|
+
if (!address) return postDeploy;
|
|
1092
|
+
return postDeploy.split("{{url}}").join(address);
|
|
1045
1093
|
}
|
|
1046
1094
|
/**
|
|
1047
1095
|
* Normalise arbitrary input into a legal DNS label, returning an empty string
|
|
@@ -1410,18 +1458,25 @@ async function promptForDeclaredEnv(session, declared) {
|
|
|
1410
1458
|
return answers;
|
|
1411
1459
|
}
|
|
1412
1460
|
/**
|
|
1413
|
-
*
|
|
1461
|
+
* The stored credentials, if the platform still accepts them, with whatever it
|
|
1462
|
+
* said about the Tenant while answering.
|
|
1414
1463
|
*
|
|
1415
|
-
* Only a refusal counts as an answer. An unreachable gateway
|
|
1416
|
-
* whether the credentials are good, and treating it as a dead
|
|
1417
|
-
* a user who is merely offline through a login they do not
|
|
1464
|
+
* Only a refusal counts as an answer — that is the null. An unreachable gateway
|
|
1465
|
+
* says nothing about whether the credentials are good, and treating it as a dead
|
|
1466
|
+
* session would send a user who is merely offline through a login they do not
|
|
1467
|
+
* need, so it comes back as a session with nothing known about the Tenant.
|
|
1418
1468
|
*/
|
|
1419
|
-
async function
|
|
1469
|
+
async function probeSession(creds) {
|
|
1420
1470
|
try {
|
|
1421
|
-
|
|
1422
|
-
|
|
1471
|
+
return {
|
|
1472
|
+
creds,
|
|
1473
|
+
tenant: await fetchTenantDetails(creds)
|
|
1474
|
+
};
|
|
1423
1475
|
} catch (err) {
|
|
1424
|
-
return
|
|
1476
|
+
return err instanceof GatewayError && (err.status === 401 || err.status === 403) ? null : {
|
|
1477
|
+
creds,
|
|
1478
|
+
tenant: null
|
|
1479
|
+
};
|
|
1425
1480
|
}
|
|
1426
1481
|
}
|
|
1427
1482
|
/**
|
|
@@ -1438,7 +1493,10 @@ async function sessionIsLive(creds) {
|
|
|
1438
1493
|
*/
|
|
1439
1494
|
async function ensureSession(options) {
|
|
1440
1495
|
const stored = readCredentials();
|
|
1441
|
-
if (stored
|
|
1496
|
+
if (stored) {
|
|
1497
|
+
const probed = await probeSession(stored);
|
|
1498
|
+
if (probed) return probed;
|
|
1499
|
+
}
|
|
1442
1500
|
console.log(stored ? "\n[wawesome] Your session has expired." : "\n[wawesome] You're not logged in yet — that's what a deploy needs.");
|
|
1443
1501
|
if (!isInteractive()) {
|
|
1444
1502
|
console.log("[wawesome] Run 'wawesome login', then 'wawesome deploy'.");
|
|
@@ -1464,7 +1522,69 @@ async function ensureSession(options) {
|
|
|
1464
1522
|
console.error(`[wawesome] Login failed: ${errorText(err)}`);
|
|
1465
1523
|
return null;
|
|
1466
1524
|
}
|
|
1467
|
-
|
|
1525
|
+
const fresh = readCredentials();
|
|
1526
|
+
return fresh ? probeSession(fresh) : null;
|
|
1527
|
+
}
|
|
1528
|
+
/** Bound on the rename loop, so a name the gateway keeps refusing ends the offer. */
|
|
1529
|
+
const MAX_RENAME_ATTEMPTS = 3;
|
|
1530
|
+
/** Show the address the Function will answer on, once it is deployed. */
|
|
1531
|
+
function announceUrl(creds, slug, appSlug, functionName) {
|
|
1532
|
+
console.log("\n[wawesome] Your Function will answer on:\n");
|
|
1533
|
+
console.log(` \x1b[36m${publicAddress(creds.gateway_url, slug, appSlug, functionName)}\x1b[0m`);
|
|
1534
|
+
console.log(` ${SUBTREE_NOTE}\n`);
|
|
1535
|
+
}
|
|
1536
|
+
/**
|
|
1537
|
+
* Show the URL, and offer to fix the workspace address while it can still be fixed.
|
|
1538
|
+
*
|
|
1539
|
+
* This is the last moment that address is free: it locks the first time a
|
|
1540
|
+
* version is promoted, which is what the deploy at the end of this flow does.
|
|
1541
|
+
* Asking here rather than at signup is the whole reason naming was deferred —
|
|
1542
|
+
* it is client-facing branding, and nobody chooses it well before seeing the
|
|
1543
|
+
* product work. The URL comes first so the offer is about something concrete.
|
|
1544
|
+
*
|
|
1545
|
+
* The lock is read from the gateway rather than guessed, so a user who cannot
|
|
1546
|
+
* rename is told why instead of being walked into a rejection. Nothing here can
|
|
1547
|
+
* fail the flow: the project is already on disk and the deploy still works under
|
|
1548
|
+
* the address the workspace has.
|
|
1549
|
+
*/
|
|
1550
|
+
async function offerWorkspaceAddress(session, creds, tenant, appSlug, functionName) {
|
|
1551
|
+
const current = tenant?.tenant_slug ?? creds.tenant_slug;
|
|
1552
|
+
if (!current) return;
|
|
1553
|
+
announceUrl(creds, current, appSlug, functionName);
|
|
1554
|
+
if (!tenant) {
|
|
1555
|
+
console.log(` '${current}' is your workspace address. Whether it can still be changed`);
|
|
1556
|
+
console.log(" is a question for the gateway, which did not answer.\n");
|
|
1557
|
+
return;
|
|
1558
|
+
}
|
|
1559
|
+
if (tenant.slug_locked) {
|
|
1560
|
+
console.log(` 🔒 '${current}' is fixed — a Function version has been promoted, and live URLs already carry it.\n`);
|
|
1561
|
+
return;
|
|
1562
|
+
}
|
|
1563
|
+
console.log(` '${current}' is your workspace address — the part of that URL that is yours`);
|
|
1564
|
+
console.log(" rather than this project's, and this is the moment to change it: it locks");
|
|
1565
|
+
console.log(" for good the first time you deploy, because live URLs carry it.");
|
|
1566
|
+
console.log(" Press enter to keep it.\n");
|
|
1567
|
+
let refusal;
|
|
1568
|
+
for (let attempt = 0; attempt < MAX_RENAME_ATTEMPTS; attempt++) {
|
|
1569
|
+
const answer = await session.ask(" Workspace address?", current);
|
|
1570
|
+
if (answer === current) {
|
|
1571
|
+
console.log(`[wawesome] Keeping '${current}'.`);
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
try {
|
|
1575
|
+
const renamed = await renameTenantSlug(creds, answer);
|
|
1576
|
+
console.log(`\n[wawesome] ✅ Workspace renamed to '${renamed.tenant_slug}'.`);
|
|
1577
|
+
announceUrl(creds, renamed.tenant_slug, appSlug, functionName);
|
|
1578
|
+
return;
|
|
1579
|
+
} catch (err) {
|
|
1580
|
+
console.log(`[wawesome] ${errorText(err)}`);
|
|
1581
|
+
refusal = err instanceof GatewayError ? err.reason : void 0;
|
|
1582
|
+
const { text, retryable } = renameAdvice(refusal);
|
|
1583
|
+
if (text) console.log(`[wawesome] ${text}`);
|
|
1584
|
+
if (!retryable) break;
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
console.log(refusal === "locked" ? `[wawesome] Keeping '${current}'.` : `[wawesome] Keeping '${current}'. Change it later with: wawesome workspace rename <name>`);
|
|
1468
1588
|
}
|
|
1469
1589
|
/**
|
|
1470
1590
|
* Satisfy the template's declarations against the platform.
|
|
@@ -1538,7 +1658,7 @@ async function initFromTemplate(templateName, options) {
|
|
|
1538
1658
|
let functionName;
|
|
1539
1659
|
let appSlug;
|
|
1540
1660
|
let manifest;
|
|
1541
|
-
let
|
|
1661
|
+
let tenantSession;
|
|
1542
1662
|
let answers = [];
|
|
1543
1663
|
try {
|
|
1544
1664
|
let files;
|
|
@@ -1553,7 +1673,7 @@ async function initFromTemplate(templateName, options) {
|
|
|
1553
1673
|
}
|
|
1554
1674
|
const collisions = collidingPaths(cwd, files);
|
|
1555
1675
|
if (collisions.length > 0) fail(`${collisions.join(", ")} already exist${collisions.length === 1 ? "s" : ""} here.`, "Run this in an empty directory, or move those files aside first. Nothing was written.");
|
|
1556
|
-
|
|
1676
|
+
tenantSession = await ensureSession(options);
|
|
1557
1677
|
const session = openPromptSession();
|
|
1558
1678
|
try {
|
|
1559
1679
|
functionName = await promptForSlug(session, "Function name", readFunctionConfig(staging)?.function || dirName);
|
|
@@ -1572,7 +1692,8 @@ async function initFromTemplate(templateName, options) {
|
|
|
1572
1692
|
}
|
|
1573
1693
|
console.log(`\n[wawesome] ✅ Scaffolded ${files.length} files from '${template.name}'.`);
|
|
1574
1694
|
if (repinned) console.log(`[wawesome] Using wawesome ${repinned.to} — the template pinned ${repinned.from}.`);
|
|
1575
|
-
|
|
1695
|
+
if (tenantSession) await offerWorkspaceAddress(session, tenantSession.creds, tenantSession.tenant, appSlug, functionName);
|
|
1696
|
+
answers = tenantSession ? await promptForDeclaredEnv(session, manifest.env) : [];
|
|
1576
1697
|
} finally {
|
|
1577
1698
|
session.close();
|
|
1578
1699
|
}
|
|
@@ -1580,7 +1701,7 @@ async function initFromTemplate(templateName, options) {
|
|
|
1580
1701
|
sweepStaging();
|
|
1581
1702
|
process.off("exit", sweepStaging);
|
|
1582
1703
|
}
|
|
1583
|
-
if (!
|
|
1704
|
+
if (!tenantSession) {
|
|
1584
1705
|
const installed = options.install === false ? null : installDependencies(cwd, { verbose: options.verbose });
|
|
1585
1706
|
console.log("\n[wawesome] 🎉 Project ready. Next steps:");
|
|
1586
1707
|
[
|
|
@@ -1591,14 +1712,14 @@ async function initFromTemplate(templateName, options) {
|
|
|
1591
1712
|
console.log("");
|
|
1592
1713
|
return;
|
|
1593
1714
|
}
|
|
1594
|
-
await wireUp(creds, appSlug, manifest, answers);
|
|
1715
|
+
await wireUp(tenantSession.creds, appSlug, manifest, answers);
|
|
1595
1716
|
if (options.install !== false) installDependencies(cwd, { verbose: options.verbose });
|
|
1596
1717
|
const result = await deploy(void 0, {
|
|
1597
1718
|
out: "dist/index.js",
|
|
1598
1719
|
verbose: options.verbose
|
|
1599
1720
|
});
|
|
1600
1721
|
if (manifest.post_deploy) {
|
|
1601
|
-
console.log(renderPostDeploy(manifest.post_deploy, result.
|
|
1722
|
+
console.log(renderPostDeploy(manifest.post_deploy, result.address));
|
|
1602
1723
|
console.log("");
|
|
1603
1724
|
}
|
|
1604
1725
|
}
|
|
@@ -2366,7 +2487,10 @@ async function showWorkspace(options) {
|
|
|
2366
2487
|
console.log(` Name: ${tenant.name}`);
|
|
2367
2488
|
console.log(` Address: ${tenant.tenant_slug}`);
|
|
2368
2489
|
console.log(` Tenant: ${tenant.id}`);
|
|
2369
|
-
if (options.verbose)
|
|
2490
|
+
if (options.verbose) {
|
|
2491
|
+
console.log(` URLs: ${publicAddressTemplate(creds.gateway_url, tenant.tenant_slug)}`);
|
|
2492
|
+
console.log(` ${SUBTREE_NOTE}`);
|
|
2493
|
+
}
|
|
2370
2494
|
if (tenant.slug_locked) console.log("\n 🔒 The address is fixed — a Function version has been promoted and live URLs carry it.");
|
|
2371
2495
|
else {
|
|
2372
2496
|
console.log("\n The address can still be changed: \x1B[36mwawesome workspace rename <name>\x1B[0m");
|
|
@@ -2408,20 +2532,8 @@ async function renameWorkspace(slug, options) {
|
|
|
2408
2532
|
} catch (err) {
|
|
2409
2533
|
if (err instanceof GatewayError) {
|
|
2410
2534
|
console.error(`\n[wawesome] \x1b[31m${err.message}\x1b[0m`);
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
console.error("[wawesome] Pick a different name.");
|
|
2414
|
-
break;
|
|
2415
|
-
case "reserved":
|
|
2416
|
-
console.error("[wawesome] Pick a different name.");
|
|
2417
|
-
break;
|
|
2418
|
-
case "malformed":
|
|
2419
|
-
console.error("[wawesome] Use lowercase letters, numbers and single hyphens.");
|
|
2420
|
-
break;
|
|
2421
|
-
case "locked":
|
|
2422
|
-
console.error("[wawesome] A deploy landed while this was running, which fixed the address for good.");
|
|
2423
|
-
break;
|
|
2424
|
-
}
|
|
2535
|
+
const { text } = renameAdvice(err.reason);
|
|
2536
|
+
if (text) console.error(`[wawesome] ${text}`);
|
|
2425
2537
|
console.error("");
|
|
2426
2538
|
process.exit(1);
|
|
2427
2539
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wawesome",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"description": "CLI tool for building and deploying serverless functions on wawesome.io platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"build": "tsdown",
|
|
17
17
|
"dev": "tsdown --watch",
|
|
18
18
|
"test": "vitest run",
|
|
19
|
+
"test:templates": "vitest run --config vitest.live.config.ts",
|
|
19
20
|
"check": "publint --pack npm",
|
|
20
21
|
"changeset": "changeset"
|
|
21
22
|
},
|