layero 0.3.0 → 0.4.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/api.js +4 -0
- package/dist/bin/layero.js +9 -0
- package/dist/commands/deploy.js +40 -0
- package/dist/commands/orgs.js +24 -0
- package/package.json +1 -1
package/dist/api.js
CHANGED
|
@@ -44,6 +44,9 @@ export class ApiClient {
|
|
|
44
44
|
listProjects() {
|
|
45
45
|
return this.request("GET", "/projects");
|
|
46
46
|
}
|
|
47
|
+
listOrganizations() {
|
|
48
|
+
return this.request("GET", "/organizations");
|
|
49
|
+
}
|
|
47
50
|
getProject(idOrSlug) {
|
|
48
51
|
return this.request("GET", `/projects/${idOrSlug}`);
|
|
49
52
|
}
|
|
@@ -53,6 +56,7 @@ export class ApiClient {
|
|
|
53
56
|
slug: input.slug,
|
|
54
57
|
source_type: "cli",
|
|
55
58
|
framework_hint: input.framework_hint,
|
|
59
|
+
organization_slug: input.organization_slug,
|
|
56
60
|
});
|
|
57
61
|
}
|
|
58
62
|
initUpload(projectId) {
|
package/dist/bin/layero.js
CHANGED
|
@@ -12,6 +12,7 @@ import { tokenSetCmd } from "../commands/token.js";
|
|
|
12
12
|
import { deployCmd } from "../commands/deploy.js";
|
|
13
13
|
import { deploysListCmd, rollbackCmd } from "../commands/deploys.js";
|
|
14
14
|
import { loginCmd } from "../commands/login.js";
|
|
15
|
+
import { orgsListCmd } from "../commands/orgs.js";
|
|
15
16
|
// Read version from the shipped package.json (two levels up from dist/bin/).
|
|
16
17
|
const pkgPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "package.json");
|
|
17
18
|
const VERSION = JSON.parse(readFileSync(pkgPath, "utf-8")).version;
|
|
@@ -45,6 +46,13 @@ async function main() {
|
|
|
45
46
|
.command("list")
|
|
46
47
|
.description("List your projects.")
|
|
47
48
|
.action(projectsListCmd);
|
|
49
|
+
const orgs = program
|
|
50
|
+
.command("orgs")
|
|
51
|
+
.description("Layero organizations on your account (personal + teams).");
|
|
52
|
+
orgs
|
|
53
|
+
.command("list")
|
|
54
|
+
.description("Show every Layero organization you belong to.")
|
|
55
|
+
.action(orgsListCmd);
|
|
48
56
|
const deploys = program
|
|
49
57
|
.command("deploys")
|
|
50
58
|
.description("List and inspect deploys for the linked project.");
|
|
@@ -94,6 +102,7 @@ async function main() {
|
|
|
94
102
|
.option("--config", "use framework/build settings + env vars from .layero/project.json (skips the browser setup wizard)")
|
|
95
103
|
.option("--prod", "deploy to production (replaces apex_hostname's active deploy). Without this flag, deploys go to the project's CLI preview pseudo-branch.")
|
|
96
104
|
.option("--branch <name>", "deploy to a specific branch's environment. Wins over --prod.")
|
|
105
|
+
.option("--org <slug>", "Layero organization slug for first-time project creation. Defaults to personal; required when you're a member of multiple orgs and want a non-personal home.")
|
|
97
106
|
.addHelpText("after", "\nExamples:\n" +
|
|
98
107
|
" $ layero deploy # preview on CLI pseudo-branch (never replaces prod)\n" +
|
|
99
108
|
" $ layero deploy --prod # production deploy (interactive confirm)\n" +
|
package/dist/commands/deploy.js
CHANGED
|
@@ -100,11 +100,51 @@ async function resolveOrCreateProject(api, cwd, opts, existing) {
|
|
|
100
100
|
throw new Error("no username set on your account. open https://app.layero.ru/onboarding " +
|
|
101
101
|
"and pick one, then re-run.");
|
|
102
102
|
}
|
|
103
|
+
// Resolve target Layero organization. Three paths:
|
|
104
|
+
// * --org=slug explicit → verify membership, use it
|
|
105
|
+
// * single org → silent default (the personal account)
|
|
106
|
+
// * multiple orgs → prompt unless --yes
|
|
107
|
+
let organizationSlug = opts.org;
|
|
108
|
+
if (organizationSlug) {
|
|
109
|
+
const orgs = await api.listOrganizations();
|
|
110
|
+
if (!orgs.some((o) => o.slug === organizationSlug)) {
|
|
111
|
+
throw new Error(`you're not a member of organization "${organizationSlug}". ` +
|
|
112
|
+
`available: ${orgs.map((o) => o.slug).join(", ") || "(none)"}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
const orgs = await api.listOrganizations();
|
|
117
|
+
if (orgs.length === 0) {
|
|
118
|
+
throw new Error("no organization found on your account. finish onboarding at https://app.layero.ru/onboarding");
|
|
119
|
+
}
|
|
120
|
+
else if (orgs.length === 1) {
|
|
121
|
+
organizationSlug = orgs[0].slug;
|
|
122
|
+
}
|
|
123
|
+
else if (opts.yes || opts.config) {
|
|
124
|
+
// CI without --org: prefer personal, fall back to first.
|
|
125
|
+
organizationSlug =
|
|
126
|
+
orgs.find((o) => o.kind === "personal")?.slug ?? orgs[0].slug;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
console.log(chalk.cyan("which organization?"));
|
|
130
|
+
orgs.forEach((o, i) => {
|
|
131
|
+
const tag = o.kind === "personal" ? "personal" : "team";
|
|
132
|
+
console.log(` ${i + 1}. ${o.slug} (${tag}, ${o.my_role})`);
|
|
133
|
+
});
|
|
134
|
+
const choiceRaw = await prompt("choose number", "1");
|
|
135
|
+
const idx = Number(choiceRaw) - 1;
|
|
136
|
+
if (Number.isNaN(idx) || idx < 0 || idx >= orgs.length) {
|
|
137
|
+
throw new Error(`invalid choice "${choiceRaw}"`);
|
|
138
|
+
}
|
|
139
|
+
organizationSlug = orgs[idx].slug;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
103
142
|
const fallbackName = path.basename(cwd);
|
|
104
143
|
const name = opts.name ?? (opts.yes || opts.config ? fallbackName : await prompt("project name", fallbackName));
|
|
105
144
|
const project = await api.createCliProject({
|
|
106
145
|
name,
|
|
107
146
|
framework_hint: opts.type,
|
|
147
|
+
organization_slug: organizationSlug,
|
|
108
148
|
});
|
|
109
149
|
return { project, createdNow: true };
|
|
110
150
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { ApiClient } from "../api.js";
|
|
3
|
+
import { loadConfig } from "../config.js";
|
|
4
|
+
/** `layero orgs list` — show every Layero organization the caller belongs to.
|
|
5
|
+
*
|
|
6
|
+
* Useful before `layero deploy --org=<slug>` so the user can see which
|
|
7
|
+
* slugs to pass without leaving the terminal.
|
|
8
|
+
*/
|
|
9
|
+
export async function orgsListCmd() {
|
|
10
|
+
const cfg = await loadConfig();
|
|
11
|
+
if (!cfg.token)
|
|
12
|
+
throw new Error("not logged in. run `layero login` first.");
|
|
13
|
+
const api = new ApiClient(cfg);
|
|
14
|
+
const orgs = await api.listOrganizations();
|
|
15
|
+
if (orgs.length === 0) {
|
|
16
|
+
console.log(chalk.dim("no organizations on this account."));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
for (const o of orgs) {
|
|
20
|
+
const kindBadge = o.kind === "personal" ? chalk.dim("personal") : chalk.cyan("team");
|
|
21
|
+
const roleBadge = chalk.dim(`(${o.my_role})`);
|
|
22
|
+
console.log(` ${chalk.bold(o.slug.padEnd(20))} ${kindBadge} ${roleBadge}`);
|
|
23
|
+
}
|
|
24
|
+
}
|