@wirechunk/cli 0.0.5 → 0.0.7
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 +26401 -22042
- package/package.json +9 -8
- package/src/commands/create-extension-version.ts +0 -2
- package/src/commands/create-user.ts +89 -14
- package/src/commands/ext-dev/init-db.ts +6 -5
- package/src/core-api/api.ts +2536 -428
- package/src/main.ts +4 -3
- package/src/util.ts +1 -1
- package/tsconfig.json +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wirechunk/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"format:check": "prettier --check .",
|
|
11
11
|
"typecheck": "tsc",
|
|
12
12
|
"typecheck-src": "tsc --skipLibCheck",
|
|
13
|
+
"typecheck-src:tsgo": "tsgo --skipLibCheck",
|
|
13
14
|
"test": "echo 'no tests yet'",
|
|
14
15
|
"build": "npm run build:clean && npm run build:cli",
|
|
15
16
|
"build:clean": "rm -rf build",
|
|
@@ -23,21 +24,21 @@
|
|
|
23
24
|
"#api": "./src/core-api/api.ts"
|
|
24
25
|
},
|
|
25
26
|
"dependencies": {
|
|
26
|
-
"argon2": "^0.
|
|
27
|
+
"argon2": "^0.44.0"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
|
-
"@commander-js/extra-typings": "^
|
|
30
|
+
"@commander-js/extra-typings": "^14.0.0",
|
|
30
31
|
"@graphql-typed-document-node/core": "^3.2.0",
|
|
31
32
|
"@types/archiver": "^6.0.3",
|
|
32
33
|
"@wirechunk/backend-lib": "0.0.0",
|
|
33
34
|
"@wirechunk/lib": "0.0.0",
|
|
34
35
|
"archiver": "^7.0.1",
|
|
35
|
-
"chalk": "^5.
|
|
36
|
-
"commander": "^
|
|
36
|
+
"chalk": "^5.6.2",
|
|
37
|
+
"commander": "^14.0.2",
|
|
37
38
|
"graphql-request": "^7.1.2",
|
|
38
|
-
"slonik": "^
|
|
39
|
-
"slonik-interceptor-query-logging": "^
|
|
40
|
-
"zod": "^
|
|
39
|
+
"slonik": "^48.8.7",
|
|
40
|
+
"slonik-interceptor-query-logging": "^48.8.7",
|
|
41
|
+
"zod": "^4.1.13"
|
|
41
42
|
},
|
|
42
43
|
"publishConfig": {
|
|
43
44
|
"access": "public"
|
|
@@ -9,17 +9,24 @@ import { detailedUniqueIntegrityConstraintViolationError } from '../errors.ts';
|
|
|
9
9
|
import type { WithGlobalOptions } from '../global-options.ts';
|
|
10
10
|
import { voidSelectSchema } from '../util.ts';
|
|
11
11
|
|
|
12
|
-
const insertUserResult = z.object({
|
|
13
|
-
id: z.string(),
|
|
14
|
-
});
|
|
15
|
-
|
|
16
12
|
const findOrgResult = z.object({
|
|
17
13
|
platformId: z.string(),
|
|
18
14
|
});
|
|
19
15
|
|
|
16
|
+
// Copied from backend-lib/roles.ts for now because different zod versions.
|
|
17
|
+
const roleSchema = z.object({
|
|
18
|
+
id: z.string(),
|
|
19
|
+
name: z.string(),
|
|
20
|
+
default: z.boolean().optional().default(false),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// The schema for the platform roles configuration.
|
|
24
|
+
const rolesSchema = z.array(roleSchema);
|
|
25
|
+
|
|
20
26
|
const findPlatformResult = z.object({
|
|
21
27
|
id: z.string(),
|
|
22
28
|
name: z.string(),
|
|
29
|
+
roles: rolesSchema.nullable(),
|
|
23
30
|
});
|
|
24
31
|
|
|
25
32
|
type CreateUserOptions = {
|
|
@@ -29,7 +36,7 @@ type CreateUserOptions = {
|
|
|
29
36
|
lastName: string;
|
|
30
37
|
orgId?: string;
|
|
31
38
|
platformId?: string;
|
|
32
|
-
role
|
|
39
|
+
role?: string;
|
|
33
40
|
emailVerified: boolean;
|
|
34
41
|
pending: boolean;
|
|
35
42
|
};
|
|
@@ -52,7 +59,7 @@ export const createUser = async (
|
|
|
52
59
|
process.exit(1);
|
|
53
60
|
}
|
|
54
61
|
const password = await hashPassword(opts.password);
|
|
55
|
-
const
|
|
62
|
+
const inputRole = opts.role || '';
|
|
56
63
|
const status = opts.pending ? 'Pending' : 'Active';
|
|
57
64
|
const firstName = opts.firstName.trim();
|
|
58
65
|
if (!firstName.length) {
|
|
@@ -70,7 +77,8 @@ export const createUser = async (
|
|
|
70
77
|
let orgPrimary = false;
|
|
71
78
|
|
|
72
79
|
try {
|
|
73
|
-
const
|
|
80
|
+
const userId = cleanSmallId();
|
|
81
|
+
await db.transaction(async (db) => {
|
|
74
82
|
if (!platformId) {
|
|
75
83
|
if (!orgId) {
|
|
76
84
|
throw new Error('Either --org-id or --platform-id must be specified');
|
|
@@ -93,17 +101,61 @@ export const createUser = async (
|
|
|
93
101
|
throw new Error(`Org ID ${orgId} does not belong to platform ID ${platformId}`);
|
|
94
102
|
}
|
|
95
103
|
}
|
|
104
|
+
|
|
96
105
|
const platform = await db.maybeOne(
|
|
97
106
|
sql.type(
|
|
98
107
|
findPlatformResult,
|
|
99
|
-
)`select "id", "name" from "Platforms" where "id" = ${platformId}`,
|
|
108
|
+
)`select "id", "name", "roles" from "Platforms" where "id" = ${platformId}`,
|
|
100
109
|
);
|
|
110
|
+
|
|
101
111
|
if (!platform) {
|
|
102
112
|
throw new Error(`No platform found with ID ${platformId}`);
|
|
103
113
|
}
|
|
104
114
|
if (opts.verbose) {
|
|
105
115
|
console.log(`Found platform ${platform.name} (ID ${platform.id})`);
|
|
106
116
|
}
|
|
117
|
+
|
|
118
|
+
// Determine the role to use.
|
|
119
|
+
let roleToUse = '';
|
|
120
|
+
if (platform.roles && platform.roles.length) {
|
|
121
|
+
if (inputRole) {
|
|
122
|
+
const roleExists = platform.roles.some((r) => r.name === inputRole);
|
|
123
|
+
if (roleExists) {
|
|
124
|
+
roleToUse = inputRole;
|
|
125
|
+
} else {
|
|
126
|
+
const validRoles = platform.roles.map((r) => r.name).join(', ');
|
|
127
|
+
console.error(
|
|
128
|
+
`Error: Invalid role "${inputRole}". Valid roles for this platform are: ${validRoles}`,
|
|
129
|
+
);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
const defaultRole = platform.roles.find((r) => r.default);
|
|
134
|
+
if (defaultRole) {
|
|
135
|
+
roleToUse = defaultRole.name;
|
|
136
|
+
if (opts.verbose) {
|
|
137
|
+
console.log(`No role provided. Using default role: ${roleToUse}`);
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
// No default role exists and no role was provided.
|
|
141
|
+
if (opts.verbose) {
|
|
142
|
+
console.log(
|
|
143
|
+
'No default role exists and no role was provided. Using empty string for the role.',
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
// No roles defined for this platform.
|
|
150
|
+
if (inputRole) {
|
|
151
|
+
console.error('Error: A role was specified but no roles are defined for this platform.');
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
if (opts.verbose) {
|
|
155
|
+
console.log('No roles defined for this platform. Using empty string for the role.');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
107
159
|
if (!orgId) {
|
|
108
160
|
orgId = cleanSmallId();
|
|
109
161
|
await db.maybeOne(
|
|
@@ -117,23 +169,46 @@ export const createUser = async (
|
|
|
117
169
|
orgPrimary = true;
|
|
118
170
|
}
|
|
119
171
|
|
|
120
|
-
const user = await db.
|
|
121
|
-
sql.type(
|
|
122
|
-
|
|
123
|
-
|
|
172
|
+
const user = await db.maybeOne(
|
|
173
|
+
sql.type(voidSelectSchema)`insert into "Users" (
|
|
174
|
+
"id",
|
|
175
|
+
"platformId",
|
|
176
|
+
"email",
|
|
177
|
+
"emailVerified",
|
|
178
|
+
"password",
|
|
179
|
+
"passwordStatus",
|
|
180
|
+
"orgId",
|
|
181
|
+
"role",
|
|
182
|
+
"status",
|
|
183
|
+
"firstName",
|
|
184
|
+
"lastName"
|
|
185
|
+
)
|
|
186
|
+
values (
|
|
187
|
+
${userId},
|
|
188
|
+
${platformId},
|
|
189
|
+
${email},
|
|
190
|
+
${opts.emailVerified},
|
|
191
|
+
${password},
|
|
192
|
+
'Ok',
|
|
193
|
+
${orgId},
|
|
194
|
+
${roleToUse},
|
|
195
|
+
${status},
|
|
196
|
+
${firstName},
|
|
197
|
+
${lastName}
|
|
198
|
+
)`,
|
|
124
199
|
);
|
|
125
200
|
|
|
126
201
|
if (orgPrimary) {
|
|
127
202
|
await db.maybeOne(
|
|
128
203
|
sql.type(
|
|
129
204
|
voidSelectSchema,
|
|
130
|
-
)`update "Orgs" set "primaryUserId" = ${
|
|
205
|
+
)`update "Orgs" set "primaryUserId" = ${userId} where "id" = ${orgId}`,
|
|
131
206
|
);
|
|
132
207
|
}
|
|
133
208
|
|
|
134
209
|
return user;
|
|
135
210
|
});
|
|
136
|
-
console.log(`Created user (ID ${
|
|
211
|
+
console.log(`Created user (ID ${userId})`);
|
|
137
212
|
} catch (e) {
|
|
138
213
|
if (e instanceof UniqueIntegrityConstraintViolationError) {
|
|
139
214
|
console.error(detailedUniqueIntegrityConstraintViolationError(e));
|
|
@@ -37,13 +37,14 @@ const initExtDb = async ({
|
|
|
37
37
|
|
|
38
38
|
const extRoleIdent = sql.identifier([extensionRoleName]);
|
|
39
39
|
|
|
40
|
+
// Note the password_required 'false' option is needed for local development environments without passwords.
|
|
40
41
|
await db.query(sql.unsafe`
|
|
41
42
|
create user mapping if not exists for ${extRoleIdent} server wirechunk
|
|
42
43
|
options (user ${sql.literalValue(extensionRoleName)}, password_required 'false')
|
|
43
44
|
`);
|
|
44
45
|
await db.query(sql.unsafe`
|
|
45
46
|
create foreign table if not exists "Users" (
|
|
46
|
-
"id"
|
|
47
|
+
"id" text not null,
|
|
47
48
|
"firstName" text not null,
|
|
48
49
|
"lastName" text not null,
|
|
49
50
|
"email" text not null,
|
|
@@ -59,7 +60,7 @@ const initExtDb = async ({
|
|
|
59
60
|
create foreign table if not exists "Orgs" (
|
|
60
61
|
"id" text not null,
|
|
61
62
|
"name" text,
|
|
62
|
-
"primaryUserId"
|
|
63
|
+
"primaryUserId" text,
|
|
63
64
|
"createdAt" timestamptz not null
|
|
64
65
|
) server wirechunk options (schema_name 'public', table_name 'Orgs')
|
|
65
66
|
`);
|
|
@@ -217,11 +218,11 @@ export const initDb = async (
|
|
|
217
218
|
db,
|
|
218
219
|
});
|
|
219
220
|
|
|
220
|
-
const
|
|
221
|
-
|
|
221
|
+
const superExtDb = new URL(extDb.url);
|
|
222
|
+
superExtDb.username = coreDbUrlObject.username;
|
|
222
223
|
|
|
223
224
|
await initExtDb({
|
|
224
|
-
db: await createPool(
|
|
225
|
+
db: await createPool(superExtDb.toString(), dbPoolOptions(opts)),
|
|
225
226
|
extensionRoleName: extRole,
|
|
226
227
|
coreDbUrl: coreDbUrlObject,
|
|
227
228
|
});
|