@wirechunk/cli 0.0.4 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirechunk/cli",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -2,10 +2,7 @@ import { randomUUID } from 'node:crypto';
2
2
  import { cleanTinyId } from '@wirechunk/lib/clean-small-id.ts';
3
3
  import { normalizeDomain } from '@wirechunk/lib/domains.ts';
4
4
  import { normalizeEmailAddress } from '@wirechunk/lib/emails.ts';
5
- import {
6
- defaultFormattedDataTemplate,
7
- defaultNotificationEmailBodyTemplate,
8
- } from '@wirechunk/lib/mixer/form-formatting-templates.ts';
5
+ import { defaultNotificationEmailBodyTemplate } from '@wirechunk/lib/mixer/form-formatting-templates.ts';
9
6
  import type { DatabasePool } from 'slonik';
10
7
  import { createPool, sql } from 'slonik';
11
8
  import type { Env } from '../env.ts';
@@ -65,9 +62,22 @@ export const bootstrap = async (
65
62
 
66
63
  await db.transaction(async (db) => {
67
64
  await db.query(
68
- sql.type(
69
- voidSelectSchema,
70
- )`insert into "Platforms" ("id", "handle", "name", "defaultFormFormattedDataTemplate", "defaultFormNotificationEmailBodyTemplate", "emailSendFromAddress") values (${platformId}, ${handle}, ${name}, ${defaultFormattedDataTemplate}, ${defaultNotificationEmailBodyTemplate}, ${emailSendFrom})`,
65
+ sql.type(voidSelectSchema)`
66
+ insert into "Platforms" (
67
+ "id",
68
+ "handle",
69
+ "name",
70
+ "defaultFormNotificationEmailBodyTemplate",
71
+ "emailSendFromAddress"
72
+ )
73
+ values (
74
+ ${platformId},
75
+ ${handle},
76
+ ${name},
77
+ ${defaultNotificationEmailBodyTemplate},
78
+ ${emailSendFrom}
79
+ )
80
+ `,
71
81
  );
72
82
  });
73
83
 
@@ -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: string;
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 { role } = opts;
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 user = await db.transaction(async (db) => {
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.one(
121
- sql.type(
122
- insertUserResult,
123
- )`insert into "Users" ("platformId", "email", "emailVerified", "password", "passwordStatus", "orgId", "role", "status", "firstName", "lastName") values (${platformId}, ${email}, ${opts.emailVerified}, ${password}, 'Ok', ${orgId}, ${role}, ${status}, ${firstName}, ${lastName}) returning "id"`,
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" = ${user.id} where "id" = ${orgId}`,
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 ${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" uuid not null,
46
+ "id" text not null,
47
47
  "firstName" text not null,
48
48
  "lastName" text not null,
49
49
  "email" text not null,
@@ -65,7 +65,7 @@ const initExtDb = async ({
65
65
  `);
66
66
  await db.query(sql.unsafe`
67
67
  create foreign table if not exists "Sites" (
68
- "id" uuid not null,
68
+ "id" text not null,
69
69
  "domain" text not null,
70
70
  "orgId" text,
71
71
  "name" text not null,