@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidxai/core",
3
- "version": "0.1.16-beta.3",
3
+ "version": "0.1.16",
4
4
  "description": "This module is a NestJS module containing all the required core providers required by a Solid application",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,26 +1,17 @@
1
- import { IsEmail, IsEnum, IsJSON, IsNotEmpty, IsOptional, IsString } from 'class-validator';
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
- * Where an extension user provider is registered it is the authority on that app's user
95
- * roles, so every provider-backed intent asks it. `defaultRole` is the *fallback* for
96
- * when it names none - or when there is no provider at all - not the rule.
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.Provider,
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. Reading dto.roles as a preference or fallback would skip
281
- // roles(), which is where a provider validates its discriminator, and
282
- // CreateUserDto types roles as UpdateRoleMetadataDto[] where performSignUp
283
- // expects role-name strings. [] here falls through to `defaultRole`.
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
- if (roles.length) {
812
- await this.userService.addRolesToUser(user.username, roles);
813
- } else {
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 the fallback in populateForSignup, which this path does not go through.
852
- entity.fullName = signUpDto.fullName?.trim() || signUpDto.username;
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