@platforma-sdk/pl-cli 0.7.70 → 0.7.71
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/bin/run.mjs +5 -7
- package/dist/base_command.d.ts +31 -42
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +181 -247
- package/dist/cli.js.map +1 -1
- package/dist/cmd/admin/copy-project.d.ts +2 -16
- package/dist/cmd/project/delete.d.ts +2 -18
- package/dist/cmd/project/duplicate.d.ts +2 -19
- package/dist/cmd/project/info.d.ts +2 -17
- package/dist/cmd/project/list.d.ts +2 -14
- package/dist/cmd/project/rename.d.ts +2 -18
- package/dist/cmd-opts.d.ts +7 -17
- package/package.json +5 -25
- package/src/base_command.ts +58 -78
- package/src/cli.ts +32 -0
- package/src/cmd/admin/copy-project.ts +75 -76
- package/src/cmd/project/delete.ts +45 -48
- package/src/cmd/project/duplicate.ts +52 -59
- package/src/cmd/project/info.ts +40 -42
- package/src/cmd/project/list.ts +44 -39
- package/src/cmd/project/rename.ts +23 -30
- package/src/cmd-opts.ts +37 -54
- package/dist/cmd/index.d.ts +0 -14
- package/src/cmd/index.ts +0 -17
package/bin/run.mjs
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { run
|
|
3
|
+
import { run } from "../dist/cli.js";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
.
|
|
8
|
-
|
|
9
|
-
})
|
|
10
|
-
.finally(async () => flush());
|
|
5
|
+
run(process.argv).catch((error) => {
|
|
6
|
+
console.error(`error: ${error?.message ?? error}`);
|
|
7
|
+
process.exitCode = 1;
|
|
8
|
+
});
|
package/dist/base_command.d.ts
CHANGED
|
@@ -1,43 +1,32 @@
|
|
|
1
|
-
import { Command } from '@oclif/core';
|
|
2
1
|
import { PlClient, SignedResourceId } from '@milaboratories/pl-client';
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
password?: string;
|
|
35
|
-
"admin-user"?: string;
|
|
36
|
-
"admin-password"?: string;
|
|
37
|
-
"target-user"?: string;
|
|
38
|
-
}): Promise<{
|
|
39
|
-
pl: PlClient;
|
|
40
|
-
projectListRid: SignedResourceId;
|
|
41
|
-
}>;
|
|
42
|
-
protected finally(_: Error | undefined): Promise<void>;
|
|
43
|
-
}
|
|
2
|
+
/**
|
|
3
|
+
* Low-level: get an authenticated PlClient without resolving a project list.
|
|
4
|
+
* Use this for commands that navigate to multiple users (e.g. admin copy-project).
|
|
5
|
+
*
|
|
6
|
+
* Callers own the returned client and must `await pl.close()` when done.
|
|
7
|
+
*/
|
|
8
|
+
export declare function connectClient(flags: {
|
|
9
|
+
address: string;
|
|
10
|
+
user?: string;
|
|
11
|
+
password?: string;
|
|
12
|
+
adminUser?: string;
|
|
13
|
+
adminPassword?: string;
|
|
14
|
+
}): Promise<PlClient>;
|
|
15
|
+
/**
|
|
16
|
+
* Connect and resolve the project list for a single user.
|
|
17
|
+
* In admin mode (--admin-user + --admin-password + --target-user), operates on the target user's data.
|
|
18
|
+
* In user mode, operates on the authenticated user's own data.
|
|
19
|
+
*
|
|
20
|
+
* Callers own the returned client and must `await pl.close()` when done.
|
|
21
|
+
*/
|
|
22
|
+
export declare function connect(flags: {
|
|
23
|
+
address: string;
|
|
24
|
+
user?: string;
|
|
25
|
+
password?: string;
|
|
26
|
+
adminUser?: string;
|
|
27
|
+
adminPassword?: string;
|
|
28
|
+
targetUser?: string;
|
|
29
|
+
}): Promise<{
|
|
30
|
+
pl: PlClient;
|
|
31
|
+
projectListRid: SignedResourceId;
|
|
32
|
+
}>;
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
CHANGED
|
@@ -1,106 +1,59 @@
|
|
|
1
1
|
import { a as e, c as t, d as n, f as r, g as i, h as a, i as o, l as s, m as c, n as l, o as u, p as d, r as f, s as p, t as m, u as h } from "./output-Npj-8KEL.js";
|
|
2
|
-
import {
|
|
3
|
-
import { field as
|
|
4
|
-
import { ProjectMetaKey as
|
|
5
|
-
import { randomUUID as
|
|
6
|
-
import { createInterface as
|
|
7
|
-
//#region src/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}),
|
|
28
|
-
password: v.string({
|
|
29
|
-
char: "p",
|
|
30
|
-
summary: "Password for authentication",
|
|
31
|
-
env: "PL_PASSWORD"
|
|
32
|
-
})
|
|
33
|
-
}, E = {
|
|
34
|
-
"admin-user": v.string({
|
|
35
|
-
summary: "Admin/controller username",
|
|
36
|
-
env: "PL_ADMIN_USER",
|
|
37
|
-
required: !0
|
|
38
|
-
}),
|
|
39
|
-
"admin-password": v.string({
|
|
40
|
-
summary: "Admin/controller password",
|
|
41
|
-
env: "PL_ADMIN_PASSWORD",
|
|
42
|
-
required: !0
|
|
43
|
-
})
|
|
44
|
-
}, D = {
|
|
45
|
-
"admin-user": v.string({
|
|
46
|
-
summary: "Admin/controller username (enables admin mode)",
|
|
47
|
-
env: "PL_ADMIN_USER"
|
|
48
|
-
}),
|
|
49
|
-
"admin-password": v.string({
|
|
50
|
-
summary: "Admin/controller password",
|
|
51
|
-
env: "PL_ADMIN_PASSWORD"
|
|
52
|
-
}),
|
|
53
|
-
"target-user": v.string({
|
|
54
|
-
summary: "Operate on this user's data (requires admin credentials)",
|
|
55
|
-
env: "PL_TARGET_USER"
|
|
56
|
-
})
|
|
57
|
-
}, O = class extends _ {
|
|
58
|
-
static baseFlags = {
|
|
59
|
-
...w,
|
|
60
|
-
...T,
|
|
61
|
-
...D
|
|
2
|
+
import { Command as g, Option as _ } from "commander";
|
|
3
|
+
import { field as v, resourceIdToString as y } from "@milaboratories/pl-client";
|
|
4
|
+
import { ProjectMetaKey as b } from "@milaboratories/pl-middle-layer";
|
|
5
|
+
import { randomUUID as x } from "node:crypto";
|
|
6
|
+
import { createInterface as S } from "node:readline";
|
|
7
|
+
//#region src/base_command.ts
|
|
8
|
+
async function C(e) {
|
|
9
|
+
return e.adminUser && e.adminPassword ? a({
|
|
10
|
+
address: e.address,
|
|
11
|
+
adminUser: e.adminUser,
|
|
12
|
+
adminPassword: e.adminPassword
|
|
13
|
+
}) : i({
|
|
14
|
+
address: e.address,
|
|
15
|
+
user: e.user,
|
|
16
|
+
password: e.password
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
async function w(e) {
|
|
20
|
+
let t = !!e.adminUser, n = !!e.adminPassword, i = !!e.targetUser;
|
|
21
|
+
if (i && !(t && n)) throw Error("--target-user requires --admin-user and --admin-password");
|
|
22
|
+
if ((t || n) && !i) throw Error("--admin-user/--admin-password require --target-user for project commands");
|
|
23
|
+
let a = await C(e), o;
|
|
24
|
+
return o = i ? (await r(a, e.targetUser)).projectListRid : await h(a), {
|
|
25
|
+
pl: a,
|
|
26
|
+
projectListRid: o
|
|
62
27
|
};
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
let
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
async finally(e) {
|
|
87
|
-
this._pl && await this._pl.close();
|
|
88
|
-
}
|
|
89
|
-
}, k = {
|
|
90
|
-
"project:list": class e extends O {
|
|
91
|
-
static description = "List all projects for the authenticated user.";
|
|
92
|
-
static flags = { ...O.baseFlags };
|
|
93
|
-
async run() {
|
|
94
|
-
let { flags: t } = await this.parse(e), { pl: r, projectListRid: i } = await this.connect(t), a = await n(r, i);
|
|
95
|
-
if (t.format === "json") f(a.map((e) => ({
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/cmd-opts.ts
|
|
31
|
+
function T(e, ...t) {
|
|
32
|
+
for (let n of t) for (let t of n) e.addOption(t);
|
|
33
|
+
return e;
|
|
34
|
+
}
|
|
35
|
+
var E = () => [new _("-a, --address <url>", "Platforma server address").env("PL_ADDRESS").makeOptionMandatory(), new _("-f, --format <format>", "Output format").choices(["text", "json"]).default("text")], D = () => [new _("-u, --user <user>", "Username for authentication").env("PL_USER"), new _("-p, --password <password>", "Password for authentication").env("PL_PASSWORD")], O = () => [new _("--admin-user <user>", "Admin/controller username").env("PL_ADMIN_USER").makeOptionMandatory(), new _("--admin-password <password>", "Admin/controller password").env("PL_ADMIN_PASSWORD").makeOptionMandatory()], k = () => [
|
|
36
|
+
new _("--admin-user <user>", "Admin/controller username (enables admin mode)").env("PL_ADMIN_USER"),
|
|
37
|
+
new _("--admin-password <password>", "Admin/controller password").env("PL_ADMIN_PASSWORD"),
|
|
38
|
+
new _("--target-user <user>", "Operate on this user's data (requires admin credentials)").env("PL_TARGET_USER")
|
|
39
|
+
];
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/cmd/project/list.ts
|
|
42
|
+
function A() {
|
|
43
|
+
let e = new g("list").description("List all projects for the authenticated user.");
|
|
44
|
+
return T(e, E(), D(), k()), e.action(async (e) => {
|
|
45
|
+
let { pl: t, projectListRid: r } = await w(e);
|
|
46
|
+
try {
|
|
47
|
+
let i = await n(t, r);
|
|
48
|
+
if (e.format === "json") f(i.map((e) => ({
|
|
96
49
|
id: e.id,
|
|
97
|
-
rid:
|
|
50
|
+
rid: y(e.rid),
|
|
98
51
|
label: e.label,
|
|
99
52
|
created: e.created.toISOString(),
|
|
100
53
|
lastModified: e.lastModified.toISOString()
|
|
101
54
|
})));
|
|
102
55
|
else {
|
|
103
|
-
if (
|
|
56
|
+
if (i.length === 0) {
|
|
104
57
|
o("No projects found.");
|
|
105
58
|
return;
|
|
106
59
|
}
|
|
@@ -110,130 +63,112 @@ var w = {
|
|
|
110
63
|
"LABEL",
|
|
111
64
|
"CREATED",
|
|
112
65
|
"LAST MODIFIED"
|
|
113
|
-
],
|
|
66
|
+
], i.map((e) => [
|
|
114
67
|
e.id,
|
|
115
|
-
|
|
68
|
+
y(e.rid),
|
|
116
69
|
e.label,
|
|
117
70
|
m(e.created),
|
|
118
71
|
m(e.lastModified)
|
|
119
|
-
]))), o(`\n${
|
|
72
|
+
]))), o(`\n${i.length} project(s)`);
|
|
120
73
|
}
|
|
74
|
+
} finally {
|
|
75
|
+
await t.close();
|
|
121
76
|
}
|
|
122
|
-
},
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
let {
|
|
132
|
-
if (
|
|
133
|
-
id:
|
|
134
|
-
rid:
|
|
135
|
-
label:
|
|
136
|
-
schemaVersion:
|
|
137
|
-
blockCount:
|
|
138
|
-
blockIds:
|
|
139
|
-
created:
|
|
140
|
-
lastModified:
|
|
77
|
+
}), e;
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region src/cmd/project/info.ts
|
|
81
|
+
function j() {
|
|
82
|
+
let e = new g("info").description("Show detailed information about a project.");
|
|
83
|
+
return e.argument("<project>", "Project ID or label"), T(e, E(), D(), k()), e.action(async (e, t) => {
|
|
84
|
+
let { pl: n, projectListRid: r } = await w(t);
|
|
85
|
+
try {
|
|
86
|
+
let { id: i, rid: a } = await c(n, r, e), l = await s(n, i, a);
|
|
87
|
+
if (t.format === "json") f({
|
|
88
|
+
id: l.id,
|
|
89
|
+
rid: y(l.rid),
|
|
90
|
+
label: l.label,
|
|
91
|
+
schemaVersion: l.schemaVersion,
|
|
92
|
+
blockCount: l.blockCount,
|
|
93
|
+
blockIds: l.blockIds,
|
|
94
|
+
created: l.created.toISOString(),
|
|
95
|
+
lastModified: l.lastModified.toISOString()
|
|
141
96
|
});
|
|
142
97
|
else {
|
|
143
|
-
if (o(`Project: ${
|
|
144
|
-
o(`Created: ${m(
|
|
98
|
+
if (o(`Project: ${l.label}`), o(`ID: ${l.id}`), o(`RID: ${y(l.rid)}`), o(`Schema: ${l.schemaVersion ?? "(unknown)"}`), o(`Blocks: ${l.blockCount}`), l.blockIds.length > 0) for (let e of l.blockIds) o(` - ${e}`);
|
|
99
|
+
o(`Created: ${m(l.created)}`), o(`Last Modified: ${m(l.lastModified)}`);
|
|
145
100
|
}
|
|
101
|
+
} finally {
|
|
102
|
+
await n.close();
|
|
146
103
|
}
|
|
147
|
-
},
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
allowNo: !0
|
|
165
|
-
})
|
|
166
|
-
};
|
|
167
|
-
async run() {
|
|
168
|
-
let { args: r, flags: i } = await this.parse(n), { pl: a, projectListRid: s } = await this.connect(i), { rid: l } = await c(a, s, r.project), u = S(), d = await a.withWriteTx("duplicateProject", async (n) => {
|
|
169
|
-
let r = await n.getKValueString(l, x), a = JSON.parse(r).label, o = await t(n, s), c;
|
|
170
|
-
if (i.name) {
|
|
171
|
-
if (!i["auto-rename"] && o.includes(i.name)) throw Error(`Project name "${i.name}" already exists.`);
|
|
172
|
-
c = o.includes(i.name) ? e(i.name, o) : i.name;
|
|
173
|
-
} else c = e(a, o);
|
|
174
|
-
let d = await p(n, l, { label: c });
|
|
175
|
-
n.createField(y(s, u), "Dynamic", d), await n.commit();
|
|
104
|
+
}), e;
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/cmd/project/duplicate.ts
|
|
108
|
+
function M() {
|
|
109
|
+
let n = new g("duplicate").description("Duplicate a project within the same user. Auto-renames on collision by default.");
|
|
110
|
+
return n.argument("<project>", "Project ID or label"), T(n, E(), D(), k()), n.option("-n, --name <name>", "Name for the duplicate"), n.addOption(new _("--auto-rename", "Auto-rename on collision (default: true)").default(!0)), n.option("--no-auto-rename", "Fail on name collision instead of auto-renaming"), n.action(async (n, r) => {
|
|
111
|
+
let { pl: i, projectListRid: a } = await w(r);
|
|
112
|
+
try {
|
|
113
|
+
let { rid: s } = await c(i, a, n), l = x(), u = await i.withWriteTx("duplicateProject", async (n) => {
|
|
114
|
+
let i = await n.getKValueString(s, b), o = JSON.parse(i).label, c = await t(n, a), u;
|
|
115
|
+
if (r.name) {
|
|
116
|
+
if (!r.autoRename && c.includes(r.name)) throw Error(`Project name "${r.name}" already exists.`);
|
|
117
|
+
u = c.includes(r.name) ? e(r.name, c) : r.name;
|
|
118
|
+
} else u = e(o, c);
|
|
119
|
+
let d = await p(n, s, { label: u });
|
|
120
|
+
n.createField(v(a, l), "Dynamic", d), await n.commit();
|
|
176
121
|
let f = await d.globalId;
|
|
177
122
|
return {
|
|
178
|
-
id:
|
|
123
|
+
id: y(f),
|
|
179
124
|
rid: f,
|
|
180
|
-
label:
|
|
125
|
+
label: u
|
|
181
126
|
};
|
|
182
127
|
});
|
|
183
|
-
|
|
184
|
-
id:
|
|
185
|
-
rid:
|
|
186
|
-
label:
|
|
187
|
-
}) : o(`Duplicated project as "${
|
|
128
|
+
r.format === "json" ? f({
|
|
129
|
+
id: u.id,
|
|
130
|
+
rid: y(u.rid),
|
|
131
|
+
label: u.label
|
|
132
|
+
}) : o(`Duplicated project as "${u.label}" (id: ${u.id})`);
|
|
133
|
+
} finally {
|
|
134
|
+
await i.close();
|
|
188
135
|
}
|
|
189
|
-
},
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
})
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
let { args: t, flags: n } = await this.parse(e), { pl: r, projectListRid: i } = await this.connect(n), { id: a, rid: s } = await c(r, i, t.project);
|
|
207
|
-
await d(r, s, n.name), n.format === "json" ? f({
|
|
208
|
-
id: a,
|
|
209
|
-
rid: b(s),
|
|
210
|
-
label: n.name
|
|
211
|
-
}) : o(`Renamed project to "${n.name}"`);
|
|
136
|
+
}), n;
|
|
137
|
+
}
|
|
138
|
+
//#endregion
|
|
139
|
+
//#region src/cmd/project/rename.ts
|
|
140
|
+
function N() {
|
|
141
|
+
let e = new g("rename").description("Rename a project.");
|
|
142
|
+
return e.argument("<project>", "Project ID or label"), T(e, E(), D(), k()), e.addOption(new _("-n, --name <name>", "New name for the project").makeOptionMandatory()), e.action(async (e, t) => {
|
|
143
|
+
let { pl: n, projectListRid: r } = await w(t);
|
|
144
|
+
try {
|
|
145
|
+
let { id: i, rid: a } = await c(n, r, e);
|
|
146
|
+
await d(n, a, t.name), t.format === "json" ? f({
|
|
147
|
+
id: i,
|
|
148
|
+
rid: y(a),
|
|
149
|
+
label: t.name
|
|
150
|
+
}) : o(`Renamed project to "${t.name}"`);
|
|
151
|
+
} finally {
|
|
152
|
+
await n.close();
|
|
212
153
|
}
|
|
213
|
-
},
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
})
|
|
226
|
-
};
|
|
227
|
-
async run() {
|
|
228
|
-
let { args: t, flags: n } = await this.parse(e), { pl: r, projectListRid: i } = await this.connect(n), { id: a, rid: l, fieldName: d } = await c(r, i, t.project), p = await s(r, a, l);
|
|
229
|
-
if (!n.force) {
|
|
230
|
-
let e = C({
|
|
154
|
+
}), e;
|
|
155
|
+
}
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/cmd/project/delete.ts
|
|
158
|
+
function P() {
|
|
159
|
+
let e = new g("delete").description("Delete a project. This permanently destroys all project data.");
|
|
160
|
+
return e.argument("<project>", "Project ID or label"), T(e, E(), D(), k()), e.option("--force", "Skip confirmation", !1), e.action(async (e, t) => {
|
|
161
|
+
let { pl: n, projectListRid: r } = await w(t);
|
|
162
|
+
try {
|
|
163
|
+
let { id: i, rid: a, fieldName: l } = await c(n, r, e), d = await s(n, i, a);
|
|
164
|
+
if (!t.force) {
|
|
165
|
+
let e = S({
|
|
231
166
|
input: process.stdin,
|
|
232
167
|
output: process.stderr
|
|
233
168
|
});
|
|
234
169
|
try {
|
|
235
170
|
if ((await new Promise((t) => {
|
|
236
|
-
e.question(`Delete project "${
|
|
171
|
+
e.question(`Delete project "${d.label}" (${d.blockCount} blocks)? [y/N] `, t);
|
|
237
172
|
})).toLowerCase() !== "y") {
|
|
238
173
|
o("Aborted.");
|
|
239
174
|
return;
|
|
@@ -242,65 +177,64 @@ var w = {
|
|
|
242
177
|
e.close();
|
|
243
178
|
}
|
|
244
179
|
}
|
|
245
|
-
await u(
|
|
180
|
+
await u(n, r, l), t.format === "json" ? f({
|
|
246
181
|
deleted: !0,
|
|
247
|
-
id:
|
|
248
|
-
label:
|
|
249
|
-
}) : o(`Deleted project "${
|
|
182
|
+
id: i,
|
|
183
|
+
label: d.label
|
|
184
|
+
}) : o(`Deleted project "${d.label}"`);
|
|
185
|
+
} finally {
|
|
186
|
+
await n.close();
|
|
250
187
|
}
|
|
251
|
-
},
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}),
|
|
261
|
-
|
|
262
|
-
summary: "Source project ID or label",
|
|
263
|
-
required: !0
|
|
264
|
-
}),
|
|
265
|
-
"target-user": v.string({ summary: "Username of the target user (defaults to source-user for same-user copy)" }),
|
|
266
|
-
name: v.string({
|
|
267
|
-
char: "n",
|
|
268
|
-
summary: "Name for the copied project",
|
|
269
|
-
helpValue: "<name>"
|
|
270
|
-
}),
|
|
271
|
-
"auto-rename": v.boolean({
|
|
272
|
-
summary: "Auto-rename on collision (default: true)",
|
|
273
|
-
default: !0,
|
|
274
|
-
allowNo: !0
|
|
275
|
-
})
|
|
276
|
-
};
|
|
277
|
-
async run() {
|
|
278
|
-
let { flags: i } = await this.parse(n), a = await this.connectClient(i), s = i["target-user"] ?? i["source-user"], l = await r(a, i["source-user"]), { rid: u } = await c(a, l.projectListRid, i["source-project"]), d = s === i["source-user"] ? l : await r(a, s), m = S(), h = await a.withWriteTx("adminCopyProject", async (n) => {
|
|
279
|
-
let r = await n.getKValueString(u, x), a = JSON.parse(r).label, o = await t(n, d.projectListRid), s = i.name ?? a;
|
|
188
|
+
}), e;
|
|
189
|
+
}
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region src/cmd/admin/copy-project.ts
|
|
192
|
+
function F() {
|
|
193
|
+
let n = new g("copy-project").description("Copy a project from one user to another. Requires admin/controller credentials.");
|
|
194
|
+
return T(n, E(), O()), n.addOption(new _("--source-user <user>", "Username of the source project owner").makeOptionMandatory()), n.addOption(new _("--source-project <project>", "Source project ID or label").makeOptionMandatory()), n.option("--target-user <user>", "Username of the target user (defaults to source-user for same-user copy)"), n.option("-n, --name <name>", "Name for the copied project"), n.addOption(new _("--auto-rename", "Auto-rename on collision (default: true)").default(!0)), n.option("--no-auto-rename", "Fail on name collision instead of auto-renaming"), n.action(async (n) => {
|
|
195
|
+
let i = await C(n);
|
|
196
|
+
try {
|
|
197
|
+
let a = n.targetUser ?? n.sourceUser, s = await r(i, n.sourceUser), { rid: l } = await c(i, s.projectListRid, n.sourceProject), u = a === n.sourceUser ? s : await r(i, a), d = x(), m = await i.withWriteTx("adminCopyProject", async (r) => {
|
|
198
|
+
let i = await r.getKValueString(l, b), a = JSON.parse(i).label, o = await t(r, u.projectListRid), s = n.name ?? a;
|
|
280
199
|
if (o.includes(s)) {
|
|
281
|
-
if (!
|
|
282
|
-
s = e(
|
|
200
|
+
if (!n.autoRename) throw Error(`Project name "${s}" already exists for target user.`);
|
|
201
|
+
s = e(n.name ?? a, o);
|
|
283
202
|
}
|
|
284
|
-
let c = await p(
|
|
285
|
-
|
|
286
|
-
let
|
|
203
|
+
let c = await p(r, l, { label: s });
|
|
204
|
+
r.createField(v(u.projectListRid, d), "Dynamic", c), await r.commit();
|
|
205
|
+
let f = await c.globalId;
|
|
287
206
|
return {
|
|
288
|
-
id:
|
|
289
|
-
rid:
|
|
207
|
+
id: y(f),
|
|
208
|
+
rid: f,
|
|
290
209
|
label: s
|
|
291
210
|
};
|
|
292
211
|
});
|
|
293
|
-
|
|
294
|
-
id:
|
|
295
|
-
rid:
|
|
296
|
-
label:
|
|
297
|
-
sourceUser:
|
|
298
|
-
targetUser:
|
|
299
|
-
}) : o(`Copied project from ${
|
|
212
|
+
n.format === "json" ? f({
|
|
213
|
+
id: m.id,
|
|
214
|
+
rid: y(m.rid),
|
|
215
|
+
label: m.label,
|
|
216
|
+
sourceUser: n.sourceUser,
|
|
217
|
+
targetUser: a
|
|
218
|
+
}) : o(`Copied project from ${n.sourceUser} to ${a} as "${m.label}" (id: ${m.id}, rid: ${y(m.rid)})`);
|
|
219
|
+
} finally {
|
|
220
|
+
await i.close();
|
|
300
221
|
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
222
|
+
}), n;
|
|
223
|
+
}
|
|
224
|
+
//#endregion
|
|
225
|
+
//#region src/cli.ts
|
|
226
|
+
function I() {
|
|
227
|
+
let e = new g();
|
|
228
|
+
e.name("pl-cli").description("Platforma command-line client");
|
|
229
|
+
let t = new g("project").description("Manage projects");
|
|
230
|
+
t.addCommand(A()), t.addCommand(j()), t.addCommand(M()), t.addCommand(N()), t.addCommand(P()), e.addCommand(t);
|
|
231
|
+
let n = new g("admin").description("Admin operations (requires controller credentials)");
|
|
232
|
+
return n.addCommand(F()), e.addCommand(n), e;
|
|
233
|
+
}
|
|
234
|
+
async function L(e = process.argv) {
|
|
235
|
+
await I().parseAsync(e);
|
|
236
|
+
}
|
|
303
237
|
//#endregion
|
|
304
|
-
export {
|
|
238
|
+
export { I as buildProgram, L as run };
|
|
305
239
|
|
|
306
240
|
//# sourceMappingURL=cli.js.map
|