@solidxai/core 0.1.16-beta.3 → 0.1.16
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/CHANGELOG.md +1 -3
- package/dist/dtos/otp-sign-up.dto.d.ts +0 -1
- package/dist/dtos/otp-sign-up.dto.d.ts.map +1 -1
- package/dist/dtos/otp-sign-up.dto.js +1 -12
- package/dist/dtos/otp-sign-up.dto.js.map +1 -1
- package/dist/services/authentication.service.d.ts.map +1 -1
- package/dist/services/authentication.service.js +6 -15
- package/dist/services/authentication.service.js.map +1 -1
- package/package.json +1 -1
- package/src/dtos/otp-sign-up.dto.ts +1 -11
- package/src/services/authentication.service.ts +26 -61
- package/CLAUDE.md +0 -26
- package/postman/signup-intent-verification.postman_collection.json +0 -573
- package/postman/signup-issues +0 -3
package/package.json
CHANGED
|
@@ -1,26 +1,17 @@
|
|
|
1
|
-
import { IsEmail, IsEnum, IsJSON, IsNotEmpty, IsOptional
|
|
1
|
+
import { IsEmail, IsEnum, IsJSON, IsNotEmpty, IsOptional } from 'class-validator';
|
|
2
2
|
|
|
3
3
|
import { PasswordlessRegistrationValidateWhatSources } from "../constants";
|
|
4
|
-
import { ApiProperty } from '@nestjs/swagger';
|
|
5
4
|
|
|
6
5
|
export class OTPSignUpDto {
|
|
7
|
-
@IsOptional()
|
|
8
|
-
@IsString()
|
|
9
|
-
@ApiProperty()
|
|
10
|
-
fullName: string;
|
|
11
|
-
|
|
12
6
|
@IsNotEmpty()
|
|
13
|
-
@ApiProperty()
|
|
14
7
|
username: string;
|
|
15
8
|
|
|
16
9
|
@IsOptional()
|
|
17
10
|
@IsEmail()
|
|
18
|
-
@ApiProperty()
|
|
19
11
|
email: string;
|
|
20
12
|
|
|
21
13
|
@IsOptional()
|
|
22
14
|
@IsNotEmpty()
|
|
23
|
-
@ApiProperty()
|
|
24
15
|
mobile: string;
|
|
25
16
|
|
|
26
17
|
@IsOptional()
|
|
@@ -28,6 +19,5 @@ export class OTPSignUpDto {
|
|
|
28
19
|
validationSources: PasswordlessRegistrationValidateWhatSources[] = [];
|
|
29
20
|
|
|
30
21
|
@IsOptional()
|
|
31
|
-
@ApiProperty()
|
|
32
22
|
customPayload: any;
|
|
33
23
|
}
|
|
@@ -70,18 +70,9 @@ interface otp {
|
|
|
70
70
|
|
|
71
71
|
/** Where a signup's role names come from. */
|
|
72
72
|
enum RolesSource {
|
|
73
|
-
/**
|
|
74
|
-
* Ask nobody; returning [] lets performSignUp apply the configured `defaultRole`.
|
|
75
|
-
*
|
|
76
|
-
* No intent maps here today - it is kept for paths that deliberately bypass the
|
|
77
|
-
* provider. OAuth is the live example: its DTO can never carry a discriminator, so
|
|
78
|
-
* it takes `defaultRole` outright (currently inline in UserService).
|
|
79
|
-
*/
|
|
73
|
+
/** None from the caller: performSignUp applies the configured `defaultRole`. */
|
|
80
74
|
Default,
|
|
81
|
-
/**
|
|
82
|
-
* `provider.roles(dto)` - and nothing else. Yields [] when no provider is registered
|
|
83
|
-
* or when the provider declines to name any, which falls through to `defaultRole`.
|
|
84
|
-
*/
|
|
75
|
+
/** `provider.roles(dto)`, unconditionally. */
|
|
85
76
|
Provider,
|
|
86
77
|
/** The caller's own `dto.roles`. */
|
|
87
78
|
Caller,
|
|
@@ -91,18 +82,10 @@ enum RolesSource {
|
|
|
91
82
|
* The single place that decides, per intent, which entity a signup builds and where
|
|
92
83
|
* its roles come from.
|
|
93
84
|
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* SelfRegistration and ExtensionModel resolve identically today. They stay separate
|
|
99
|
-
* intents because only SelfRegistration is gated on `allowPublicRegistration`, and
|
|
100
|
-
* because "an anonymous visitor signing themselves up" and "an admin creating a user
|
|
101
|
-
* from the model's own form" are different things that may yet need to diverge.
|
|
102
|
-
*
|
|
103
|
-
* `useProvider` is computable from `rolesSource` today (`Caller` implies false), but the
|
|
104
|
-
* two answer different questions - "which entity?" and "which roles?" - that merely
|
|
105
|
-
* coincide across these intents. Keep both, and change behaviour here, not at a call site.
|
|
85
|
+
* `useProvider` is currently computable from `rolesSource` (`Caller` implies false),
|
|
86
|
+
* but the two answer different questions - "which entity?" and "which roles?" - that
|
|
87
|
+
* merely coincide across these three intents. Keep both, and change behaviour here
|
|
88
|
+
* rather than at a call site.
|
|
106
89
|
*/
|
|
107
90
|
const SIGNUP_POLICY: Record<
|
|
108
91
|
SignupIntent,
|
|
@@ -110,7 +93,7 @@ const SIGNUP_POLICY: Record<
|
|
|
110
93
|
> = {
|
|
111
94
|
[SignupIntent.SelfRegistration]: {
|
|
112
95
|
useProvider: true,
|
|
113
|
-
rolesSource: RolesSource.
|
|
96
|
+
rolesSource: RolesSource.Default,
|
|
114
97
|
},
|
|
115
98
|
[SignupIntent.ExtensionModel]: {
|
|
116
99
|
useProvider: true,
|
|
@@ -263,24 +246,12 @@ export class AuthenticationService {
|
|
|
263
246
|
dto: Record<string, any>,
|
|
264
247
|
source: RolesSource,
|
|
265
248
|
): string[] {
|
|
266
|
-
// Only `Caller` reads dto.roles. Anywhere else, roles in the body are ignored -
|
|
267
|
-
// which is what keeps an anonymous caller from naming their own on a @Public()
|
|
268
|
-
// endpoint - so say so rather than dropping them silently.
|
|
269
|
-
if (source !== RolesSource.Caller && dto.roles?.length) {
|
|
270
|
-
this.logger.warn(
|
|
271
|
-
`Ignoring caller-supplied roles for "${dto.username}": roles on this path come from ` +
|
|
272
|
-
(source === RolesSource.Provider
|
|
273
|
-
? "the extension user provider"
|
|
274
|
-
: "the configured defaultRole"),
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
249
|
switch (source) {
|
|
279
250
|
case RolesSource.Provider:
|
|
280
|
-
// Sole authority.
|
|
281
|
-
// roles(), which is where a provider
|
|
282
|
-
// CreateUserDto types roles as
|
|
283
|
-
// expects role-name strings.
|
|
251
|
+
// Sole authority. `dto.roles` is deliberately not read - not as a preference,
|
|
252
|
+
// not as a fallback. Reading it would skip roles(), which is where a provider
|
|
253
|
+
// validates its discriminator, and CreateUserDto types roles as
|
|
254
|
+
// UpdateRoleMetadataDto[] where performSignUp expects role-name strings.
|
|
284
255
|
return (
|
|
285
256
|
this.solidRegistry
|
|
286
257
|
.getExtensionUserCreationProvider()
|
|
@@ -291,6 +262,14 @@ export class AuthenticationService {
|
|
|
291
262
|
return dto.roles ?? [];
|
|
292
263
|
|
|
293
264
|
case RolesSource.Default:
|
|
265
|
+
// Public signup: the form has no business naming roles. Returning empty lets
|
|
266
|
+
// performSignUp apply the configured `defaultRole`, rather than adding a
|
|
267
|
+
// second mechanism for the same thing.
|
|
268
|
+
if (dto.roles?.length) {
|
|
269
|
+
this.logger.warn(
|
|
270
|
+
`Ignoring caller-supplied roles on public registration for "${dto.username}"`,
|
|
271
|
+
);
|
|
272
|
+
}
|
|
294
273
|
return [];
|
|
295
274
|
}
|
|
296
275
|
}
|
|
@@ -793,31 +772,16 @@ export class AuthenticationService {
|
|
|
793
772
|
validationSource: string,
|
|
794
773
|
): Promise<User> {
|
|
795
774
|
if (isEmpty(existingUser)) {
|
|
796
|
-
// Resolved before anything is written: where a provider requires its discriminator
|
|
797
|
-
// roles() throws, and that should surface as a rejected request rather than as a
|
|
798
|
-
// half-registered user with no roles.
|
|
799
|
-
const roles = this.resolveSignupRoles(
|
|
800
|
-
signUpDto,
|
|
801
|
-
SIGNUP_POLICY[SignupIntent.SelfRegistration].rolesSource,
|
|
802
|
-
);
|
|
803
|
-
|
|
804
775
|
// A new registration is saved through whichever repository createUser resolved,
|
|
805
776
|
// which is the provider's when the app registers one.
|
|
806
777
|
const { entity: user, repo } = await this.createUser(signUpDto);
|
|
807
778
|
user.active = false; // User will be activated only after OTP verification, hence setting active to false for new user.
|
|
808
779
|
await this.assignRegistrationOtp(validationSource, user);
|
|
809
780
|
await repo.save(user);
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
// The provider named none, or there is no provider: fall back to the configured
|
|
815
|
-
// default, matching what performSignUp does on the password paths.
|
|
816
|
-
await this.userService.addRoleToUser(
|
|
817
|
-
user.username,
|
|
818
|
-
this.settingService.getConfigValue<SolidCoreSetting>("defaultRole"),
|
|
819
|
-
);
|
|
820
|
-
}
|
|
781
|
+
await this.userService.addRoleToUser(
|
|
782
|
+
user.username,
|
|
783
|
+
this.settingService.getConfigValue<SolidCoreSetting>("defaultRole"),
|
|
784
|
+
);
|
|
821
785
|
return user;
|
|
822
786
|
}
|
|
823
787
|
|
|
@@ -848,8 +812,9 @@ export class AuthenticationService {
|
|
|
848
812
|
entity.username = signUpDto.username;
|
|
849
813
|
entity.email = signUpDto.email;
|
|
850
814
|
entity.mobile = signUpDto.mobile;
|
|
851
|
-
// OTPSignUpDto declares no `fullName`, so username is the only source here. Mirrors
|
|
852
|
-
|
|
815
|
+
// OTPSignUpDto declares no `fullName`, so username is the only source here. Mirrors
|
|
816
|
+
// the fallback in populateForSignup, which this path does not go through.
|
|
817
|
+
entity.fullName = signUpDto.username;
|
|
853
818
|
entity.customPayload = signUpDto.customPayload;
|
|
854
819
|
entity.lastLoginProvider = LoginProvider.OTP;
|
|
855
820
|
|
package/CLAUDE.md
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# This is the SolidX API project.
|
|
2
|
-
This is included as a dependency in consuming projects.
|
|
3
|
-
|
|
4
|
-
# SolidX UI
|
|
5
|
-
# The corresponding UI project is at the below path:
|
|
6
|
-
/Users/oswald/projects/Solid_Starters/solid-core-ui
|
|
7
|
-
|
|
8
|
-
# SolidX Docs
|
|
9
|
-
# The documentation project is at the below path:
|
|
10
|
-
/Users/oswald/projects/solidxai-docs
|
|
11
|
-
|
|
12
|
-
# SolidX Agent
|
|
13
|
-
# The agent project which has the skills for helping users configure, build and use SolidX is at the below path:
|
|
14
|
-
/Users/oswald/projects/Solid_Starters/agent
|
|
15
|
-
|
|
16
|
-
# SolidX Control Plane Commands
|
|
17
|
-
# The control plane commands for managing SolidX instances are in the below path:
|
|
18
|
-
/Users/oswald/projects/Solid_Starters/solidctl
|
|
19
|
-
|
|
20
|
-
# Testing reference project
|
|
21
|
-
# This is the reference library management project that is used for testing and development of SolidX features. It is located at the below path:
|
|
22
|
-
/Users/oswald/projects/Solid_Starters/solid-library-management
|
|
23
|
-
|
|
24
|
-
# Code Builder project
|
|
25
|
-
# This is the project that contains the code builder which generates code based on user input and templates. It is located at the below path:
|
|
26
|
-
/Users/oswald/projects/Solid_Starters/solid-code-builder
|