@wirechunk/cli 0.0.5 → 0.0.6
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/build/main.js +122 -30
- package/package.json +1 -1
- package/src/commands/create-user.ts +80 -14
- package/src/commands/ext-dev/init-db.ts +2 -2
- package/src/core-api/api.ts +585 -88
- package/src/main.ts +4 -3
- package/tsconfig.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { hashPassword, validatePasswordComplexity } from '@wirechunk/backend-lib/passwords.ts';
|
|
2
|
+
import { rolesSchema } from '@wirechunk/backend-lib/roles.ts';
|
|
2
3
|
import { cleanSmallId } from '@wirechunk/lib/clean-small-id.ts';
|
|
3
4
|
import { normalizeEmailAddress } from '@wirechunk/lib/emails.ts';
|
|
4
5
|
import { createPool, sql, UniqueIntegrityConstraintViolationError } from 'slonik';
|
|
@@ -9,10 +10,6 @@ import { detailedUniqueIntegrityConstraintViolationError } from '../errors.ts';
|
|
|
9
10
|
import type { WithGlobalOptions } from '../global-options.ts';
|
|
10
11
|
import { voidSelectSchema } from '../util.ts';
|
|
11
12
|
|
|
12
|
-
const insertUserResult = z.object({
|
|
13
|
-
id: z.string(),
|
|
14
|
-
});
|
|
15
|
-
|
|
16
13
|
const findOrgResult = z.object({
|
|
17
14
|
platformId: z.string(),
|
|
18
15
|
});
|
|
@@ -20,6 +17,7 @@ const findOrgResult = z.object({
|
|
|
20
17
|
const findPlatformResult = z.object({
|
|
21
18
|
id: z.string(),
|
|
22
19
|
name: z.string(),
|
|
20
|
+
roles: rolesSchema.nullable(),
|
|
23
21
|
});
|
|
24
22
|
|
|
25
23
|
type CreateUserOptions = {
|
|
@@ -29,7 +27,7 @@ type CreateUserOptions = {
|
|
|
29
27
|
lastName: string;
|
|
30
28
|
orgId?: string;
|
|
31
29
|
platformId?: string;
|
|
32
|
-
role
|
|
30
|
+
role?: string;
|
|
33
31
|
emailVerified: boolean;
|
|
34
32
|
pending: boolean;
|
|
35
33
|
};
|
|
@@ -52,7 +50,7 @@ export const createUser = async (
|
|
|
52
50
|
process.exit(1);
|
|
53
51
|
}
|
|
54
52
|
const password = await hashPassword(opts.password);
|
|
55
|
-
const
|
|
53
|
+
const inputRole = opts.role || '';
|
|
56
54
|
const status = opts.pending ? 'Pending' : 'Active';
|
|
57
55
|
const firstName = opts.firstName.trim();
|
|
58
56
|
if (!firstName.length) {
|
|
@@ -70,7 +68,8 @@ export const createUser = async (
|
|
|
70
68
|
let orgPrimary = false;
|
|
71
69
|
|
|
72
70
|
try {
|
|
73
|
-
const
|
|
71
|
+
const userId = cleanSmallId();
|
|
72
|
+
await db.transaction(async (db) => {
|
|
74
73
|
if (!platformId) {
|
|
75
74
|
if (!orgId) {
|
|
76
75
|
throw new Error('Either --org-id or --platform-id must be specified');
|
|
@@ -93,17 +92,61 @@ export const createUser = async (
|
|
|
93
92
|
throw new Error(`Org ID ${orgId} does not belong to platform ID ${platformId}`);
|
|
94
93
|
}
|
|
95
94
|
}
|
|
95
|
+
|
|
96
96
|
const platform = await db.maybeOne(
|
|
97
97
|
sql.type(
|
|
98
98
|
findPlatformResult,
|
|
99
|
-
)`select "id", "name" from "Platforms" where "id" = ${platformId}`,
|
|
99
|
+
)`select "id", "name", "roles" from "Platforms" where "id" = ${platformId}`,
|
|
100
100
|
);
|
|
101
|
+
|
|
101
102
|
if (!platform) {
|
|
102
103
|
throw new Error(`No platform found with ID ${platformId}`);
|
|
103
104
|
}
|
|
104
105
|
if (opts.verbose) {
|
|
105
106
|
console.log(`Found platform ${platform.name} (ID ${platform.id})`);
|
|
106
107
|
}
|
|
108
|
+
|
|
109
|
+
// Determine the role to use.
|
|
110
|
+
let roleToUse = '';
|
|
111
|
+
if (platform.roles && platform.roles.length) {
|
|
112
|
+
if (inputRole) {
|
|
113
|
+
const roleExists = platform.roles.some((r) => r.name === inputRole);
|
|
114
|
+
if (roleExists) {
|
|
115
|
+
roleToUse = inputRole;
|
|
116
|
+
} else {
|
|
117
|
+
const validRoles = platform.roles.map((r) => r.name).join(', ');
|
|
118
|
+
console.error(
|
|
119
|
+
`Error: Invalid role "${inputRole}". Valid roles for this platform are: ${validRoles}`,
|
|
120
|
+
);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
const defaultRole = platform.roles.find((r) => r.default);
|
|
125
|
+
if (defaultRole) {
|
|
126
|
+
roleToUse = defaultRole.name;
|
|
127
|
+
if (opts.verbose) {
|
|
128
|
+
console.log(`No role provided. Using default role: ${roleToUse}`);
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
// No default role exists and no role was provided.
|
|
132
|
+
if (opts.verbose) {
|
|
133
|
+
console.log(
|
|
134
|
+
'No default role exists and no role was provided. Using empty string for the role.',
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
// No roles defined for this platform.
|
|
141
|
+
if (inputRole) {
|
|
142
|
+
console.error('Error: A role was specified but no roles are defined for this platform.');
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
if (opts.verbose) {
|
|
146
|
+
console.log('No roles defined for this platform. Using empty string for the role.');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
107
150
|
if (!orgId) {
|
|
108
151
|
orgId = cleanSmallId();
|
|
109
152
|
await db.maybeOne(
|
|
@@ -117,23 +160,46 @@ export const createUser = async (
|
|
|
117
160
|
orgPrimary = true;
|
|
118
161
|
}
|
|
119
162
|
|
|
120
|
-
const user = await db.
|
|
121
|
-
sql.type(
|
|
122
|
-
|
|
123
|
-
|
|
163
|
+
const user = await db.maybeOne(
|
|
164
|
+
sql.type(voidSelectSchema)`insert into "Users" (
|
|
165
|
+
"id",
|
|
166
|
+
"platformId",
|
|
167
|
+
"email",
|
|
168
|
+
"emailVerified",
|
|
169
|
+
"password",
|
|
170
|
+
"passwordStatus",
|
|
171
|
+
"orgId",
|
|
172
|
+
"role",
|
|
173
|
+
"status",
|
|
174
|
+
"firstName",
|
|
175
|
+
"lastName"
|
|
176
|
+
)
|
|
177
|
+
values (
|
|
178
|
+
${userId},
|
|
179
|
+
${platformId},
|
|
180
|
+
${email},
|
|
181
|
+
${opts.emailVerified},
|
|
182
|
+
${password},
|
|
183
|
+
'Ok',
|
|
184
|
+
${orgId},
|
|
185
|
+
${roleToUse},
|
|
186
|
+
${status},
|
|
187
|
+
${firstName},
|
|
188
|
+
${lastName}
|
|
189
|
+
)`,
|
|
124
190
|
);
|
|
125
191
|
|
|
126
192
|
if (orgPrimary) {
|
|
127
193
|
await db.maybeOne(
|
|
128
194
|
sql.type(
|
|
129
195
|
voidSelectSchema,
|
|
130
|
-
)`update "Orgs" set "primaryUserId" = ${
|
|
196
|
+
)`update "Orgs" set "primaryUserId" = ${userId} where "id" = ${orgId}`,
|
|
131
197
|
);
|
|
132
198
|
}
|
|
133
199
|
|
|
134
200
|
return user;
|
|
135
201
|
});
|
|
136
|
-
console.log(`Created user (ID ${
|
|
202
|
+
console.log(`Created user (ID ${userId})`);
|
|
137
203
|
} catch (e) {
|
|
138
204
|
if (e instanceof UniqueIntegrityConstraintViolationError) {
|
|
139
205
|
console.error(detailedUniqueIntegrityConstraintViolationError(e));
|
|
@@ -43,7 +43,7 @@ const initExtDb = async ({
|
|
|
43
43
|
`);
|
|
44
44
|
await db.query(sql.unsafe`
|
|
45
45
|
create foreign table if not exists "Users" (
|
|
46
|
-
"id"
|
|
46
|
+
"id" text not null,
|
|
47
47
|
"firstName" text not null,
|
|
48
48
|
"lastName" text not null,
|
|
49
49
|
"email" text not null,
|
|
@@ -59,7 +59,7 @@ const initExtDb = async ({
|
|
|
59
59
|
create foreign table if not exists "Orgs" (
|
|
60
60
|
"id" text not null,
|
|
61
61
|
"name" text,
|
|
62
|
-
"primaryUserId"
|
|
62
|
+
"primaryUserId" text,
|
|
63
63
|
"createdAt" timestamptz not null
|
|
64
64
|
) server wirechunk options (schema_name 'public', table_name 'Orgs')
|
|
65
65
|
`);
|