@silexpert/core 2.0.126-beta.0 → 2.0.126

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.
@@ -1,5 +1,5 @@
1
1
  import { t as __name } from "../rolldown-runtime-BhWHdk3m.mjs";
2
- import { FK as ReadCommercialMailTemplate, GJ as EstimateInvoiceType, PK as ReadCommercialDocumentTemplate, aq as CreatePreSaleDocument, kW as IUser, nq as CreateInvoiceDocument, rq as CreateMailHeader } from "../index-CvxgpFhm.mjs";
2
+ import { RW as IUser, UK as ReadCommercialDocumentTemplate, WK as ReadCommercialMailTemplate, dq as CreateInvoiceDocument, eY as EstimateInvoiceType, fq as CreateMailHeader, mq as CreatePreSaleDocument } from "../index-dbXTxwtd.mjs";
3
3
  import "dayjs/locale/fr.js";
4
4
  //#region ts/utils/email.d.ts
5
5
  export declare function getHoraires(user: IUser): "Du lundi au vendredi de 9h à 18h" | "Du lundi au jeudi de 9h à 17h<br/>Le vendredi de 9h à 12h";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@silexpert/core",
3
- "version": "2.0.126-beta.0",
3
+ "version": "2.0.126",
4
4
  "description": "Silex Core perform HTTP Request and object binding. Silex core helps developers to retrieve and return formatted object",
5
5
  "keywords": [
6
6
  "accounting",
@@ -18,6 +18,10 @@ import {
18
18
  GetSocietyFromUser,
19
19
  RegisterProspectBody,
20
20
  RegisterProspectResponse,
21
+ SignupBody,
22
+ ResendActivationBody,
23
+ ActivateAccountBody,
24
+ ReadActivateAccount,
21
25
  QueryGet,
22
26
  BasePaginate,
23
27
  QueryGetAllUsersPaginated,
@@ -193,6 +197,18 @@ export class User extends Resource {
193
197
  registerProspect(body: RegisterProspectBody): Promise<RegisterProspectResponse> {
194
198
  return this.axios.$post('users/prospect', body);
195
199
  }
200
+
201
+ signup(body: SignupBody): Promise<void> {
202
+ return this.axios.$post('users/signup', body);
203
+ }
204
+
205
+ resendActivation(body: ResendActivationBody): Promise<void> {
206
+ return this.axios.$post('users/signup/resend-activation', body);
207
+ }
208
+
209
+ activate(body: ActivateAccountBody): Promise<ReadActivateAccount> {
210
+ return this.axios.$post('users/signup/activate', body);
211
+ }
196
212
  updateCoworkerWorkingSchedules(idUser: number, workingSchedules: IWorkingSchedule[]): Promise<IWorkingSchedule[]> {
197
213
  return this.axios.$post(`users/coworker/${idUser}/working-schedules`, workingSchedules);
198
214
  }
@@ -2,10 +2,12 @@ export enum ExternalAuthenticationLinkPurpose {
2
2
  LOGIN = 'LOGIN',
3
3
  APPOINTMENT = 'APPOINTMENT',
4
4
  RESET_PASSWORD = 'RESET_PASSWORD',
5
+ ACTIVATION = 'ACTIVATION',
5
6
  }
6
7
 
7
8
  export enum ExternalAuthenticationLinkPurposeExpiration {
8
9
  LOGIN = 10, // 10 minutes
9
10
  APPOINTMENT = 60 * 24 * 7, // 7 days
10
11
  RESET_PASSWORD = 60 * 24 * 3, // 3 days
12
+ ACTIVATION = 60 * 24 * 7, // 7 days
11
13
  }
@@ -122,6 +122,7 @@ export enum RegistrationSourceAlias {
122
122
  RESSOURCES = 'Ressources',
123
123
  GO_ENTREPRENEURS_2026 = 'GO Entrepreneurs 2026',
124
124
  ACD = 'acd',
125
+ IN_APP_SIGNUP = 'in-app-signup',
125
126
  }
126
127
 
127
128
  /**
@@ -0,0 +1,19 @@
1
+ /** Who the prospect declares to be when signing up in-app */
2
+ export enum SignupProfile {
3
+ SOCIETY = 'SOCIETY',
4
+ ACCOUNTANT = 'ACCOUNTANT',
5
+ }
6
+
7
+ /**
8
+ * How the company of the signup was provided: picked from the company search (SIREN / SIRET known), or typed
9
+ * by the prospect when the company is not found or not registered yet.
10
+ */
11
+ export enum SignupSocietySource {
12
+ SEARCH = 'SEARCH',
13
+ MANUAL = 'MANUAL',
14
+ }
15
+
16
+ export const SignupProfileDetails = {
17
+ SOCIETY: { id: SignupProfile.SOCIETY, label: 'Entreprise' },
18
+ ACCOUNTANT: { id: SignupProfile.ACCOUNTANT, label: 'Expert-comptable' },
19
+ } as const;
@@ -1,4 +1,8 @@
1
+ import { SignupProfile } from '../../../Enum/Signup.js';
2
+
1
3
  export class CompanyMarketingInformationPayload {
4
+ /* Profile declared at the in-app signup */
5
+ declaredProfile?: SignupProfile | null;
2
6
  /* Comment nous a-t-il connu ? */
3
7
  findUs?: number | null; // 0 = Autre | 1 = Pub internet | 2 = Bouche à oreille | 3 = Presse | 4 = a cherché "expert comptable" ou un terme similaire sur un moteur de recherche et a trouvé notre site | 5 = Réseaux sociaux
4
8
  findUsDetails?: string | null;
@@ -130,12 +130,6 @@ export class UpdateOrCreateVatRegistration {
130
130
  @ToBoolean()
131
131
  @IsOptional()
132
132
  isManuallyRegistered?: boolean;
133
-
134
- // Base64-encoded PDF note; validated so non-string values are rejected instead of failing later in Buffer.from
135
- @ApiPropertyOptional()
136
- @IsString()
137
- @IsOptional()
138
- base64Note?: string | null;
139
133
  }
140
134
 
141
135
  export class CreateRegistrationDetail {
@@ -174,7 +174,7 @@ class ReferalProgramBody implements ReferalProgram {
174
174
  lastname: string;
175
175
  }
176
176
 
177
- class AnalyticsUtmBody implements Omit<Partial<IAnalyticsUtm>, 'idSociety'> {
177
+ export class AnalyticsUtmBody implements Omit<Partial<IAnalyticsUtm>, 'idSociety'> {
178
178
  @ApiPropertyOptional()
179
179
  @IsOptional()
180
180
  @IsNumber()
@@ -0,0 +1,185 @@
1
+ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
2
+ import {
3
+ IsEmail,
4
+ IsEnum,
5
+ IsNotEmpty,
6
+ IsOptional,
7
+ IsString,
8
+ Matches,
9
+ MaxLength,
10
+ Validate,
11
+ ValidateIf,
12
+ ValidateNested,
13
+ } from 'class-validator';
14
+ import { IsE164PhoneNumber } from '../../../../utils/decorators/isE164PhoneNumber.decorator.js';
15
+ import { LegalFormTypeEnum } from '../../../Enum/LegalForm.js';
16
+ import { SignupProfile, SignupSocietySource } from '../../../Enum/Signup.js';
17
+ import { AnalyticsUtmBody } from './RegisterProspect.js';
18
+
19
+ const SIREN_REGEX = /^\d{9}$/;
20
+ const SIRET_REGEX = /^\d{14}$/;
21
+ const NAME_MAX_LENGTH = 100;
22
+ const EMAIL_MAX_LENGTH = 255;
23
+ const SOCIETY_FIELD_MAX_LENGTH = 255;
24
+ const PASSWORD_MAX_LENGTH = 128;
25
+ const ZIP_CODE_REGEX = /^\d{5}$/;
26
+ const GCLID_MAX_LENGTH = 255;
27
+
28
+ const isSearchedSociety = (society: SignupSocietyBody): boolean => society.source === SignupSocietySource.SEARCH;
29
+
30
+ /**
31
+ * The company of the signup, either picked from the company search (`SEARCH`: SIREN or SIRET required, the API
32
+ * verifies and enriches it through Sirene when available) or typed by the prospect (`MANUAL`: a company not found
33
+ * or not registered yet, no identifier required). The descriptive fields are the snapshot the API falls back to
34
+ * when Sirene has no answer, so `name` is always required. `@IsOptional()` is intentionally not used on `siren`
35
+ * / `siret`: it would skip the validation when both are missing in `SEARCH` mode.
36
+ */
37
+ export class SignupSocietyBody {
38
+ @ApiProperty({ enum: SignupSocietySource, description: 'Entreprise issue de la recherche ou saisie manuellement' })
39
+ @IsEnum(SignupSocietySource)
40
+ source: SignupSocietySource;
41
+
42
+ @ApiPropertyOptional({ description: 'SIREN (9 chiffres). Requis en mode SEARCH si le SIRET est absent.' })
43
+ @ValidateIf(
44
+ (society: SignupSocietyBody) => society.siren != null || (isSearchedSociety(society) && society.siret == null),
45
+ )
46
+ @IsString()
47
+ @Matches(SIREN_REGEX, { message: 'Le SIREN doit comporter 9 chiffres' })
48
+ siren?: string;
49
+
50
+ @ApiPropertyOptional({ description: 'SIRET (14 chiffres). Requis en mode SEARCH si le SIREN est absent.' })
51
+ @ValidateIf(
52
+ (society: SignupSocietyBody) => society.siret != null || (isSearchedSociety(society) && society.siren == null),
53
+ )
54
+ @IsString()
55
+ @Matches(SIRET_REGEX, { message: 'Le SIRET doit comporter 14 chiffres' })
56
+ siret?: string;
57
+
58
+ @ApiProperty({ description: 'Raison sociale' })
59
+ @IsString()
60
+ @IsNotEmpty()
61
+ @MaxLength(SOCIETY_FIELD_MAX_LENGTH)
62
+ name: string;
63
+
64
+ @ApiPropertyOptional({ enum: LegalFormTypeEnum, description: 'Forme juridique. Requise en mode MANUAL.' })
65
+ @ValidateIf((society: SignupSocietyBody) => society.idLegalForm != null || !isSearchedSociety(society))
66
+ @IsEnum(LegalFormTypeEnum)
67
+ idLegalForm?: LegalFormTypeEnum;
68
+
69
+ @ApiPropertyOptional()
70
+ @IsOptional()
71
+ @IsString()
72
+ @MaxLength(SOCIETY_FIELD_MAX_LENGTH)
73
+ address?: string;
74
+
75
+ @ApiPropertyOptional()
76
+ @IsOptional()
77
+ @IsString()
78
+ @Matches(ZIP_CODE_REGEX, { message: 'Le code postal doit comporter 5 chiffres' })
79
+ zipCode?: string;
80
+
81
+ @ApiPropertyOptional()
82
+ @IsOptional()
83
+ @IsString()
84
+ @MaxLength(SOCIETY_FIELD_MAX_LENGTH)
85
+ city?: string;
86
+ }
87
+
88
+ export class SignupBody {
89
+ @ApiProperty()
90
+ @IsString()
91
+ @IsNotEmpty()
92
+ @MaxLength(NAME_MAX_LENGTH)
93
+ firstname: string;
94
+
95
+ @ApiProperty()
96
+ @IsString()
97
+ @IsNotEmpty()
98
+ @MaxLength(NAME_MAX_LENGTH)
99
+ lastname: string;
100
+
101
+ @ApiProperty()
102
+ @IsString()
103
+ @IsEmail()
104
+ @MaxLength(EMAIL_MAX_LENGTH)
105
+ email: string;
106
+
107
+ @ApiProperty({ description: 'Numéro au format international E.164 (ex. +33612345678)' })
108
+ @IsString()
109
+ @Validate(IsE164PhoneNumber, { message: "Le numéro de téléphone n'est pas valide" })
110
+ phone: string;
111
+
112
+ @ApiProperty({ enum: SignupProfile, description: 'Entreprise ou expert-comptable' })
113
+ @IsEnum(SignupProfile)
114
+ profile: SignupProfile;
115
+
116
+ @ApiProperty()
117
+ @IsString()
118
+ @IsNotEmpty()
119
+ @MaxLength(PASSWORD_MAX_LENGTH)
120
+ password: string;
121
+
122
+ @ApiProperty({ type: SignupSocietyBody })
123
+ @ValidateNested()
124
+ society: SignupSocietyBody;
125
+
126
+ @ApiProperty()
127
+ @IsString()
128
+ recaptcha: string;
129
+
130
+ @ApiPropertyOptional({ description: 'Cookie HubSpot `hubspotutk`' })
131
+ @IsOptional()
132
+ @IsString()
133
+ hutk?: string;
134
+
135
+ @ApiPropertyOptional({ type: AnalyticsUtmBody })
136
+ @IsOptional()
137
+ @ValidateNested()
138
+ utm?: AnalyticsUtmBody;
139
+
140
+ /** Google Ads click id, forwarded to HubSpot as `utm_gclid`; it is not stored on the society */
141
+ @ApiPropertyOptional({ description: 'Identifiant de clic Google Ads (`gclid`)' })
142
+ @IsOptional()
143
+ @IsString()
144
+ @MaxLength(GCLID_MAX_LENGTH)
145
+ gclid?: string;
146
+ }
147
+
148
+ export class ResendActivationBody {
149
+ @ApiProperty()
150
+ @IsString()
151
+ @IsEmail()
152
+ @MaxLength(EMAIL_MAX_LENGTH)
153
+ email: string;
154
+
155
+ @ApiProperty()
156
+ @IsString()
157
+ recaptcha: string;
158
+ }
159
+
160
+ /**
161
+ * The password chosen at signup is required again: the activation link alone proves ownership of the
162
+ * email, not of the signup request. It prevents a pending account created with someone else's email from
163
+ * being activated (and then used with the password the author chose) by the email owner clicking the link.
164
+ */
165
+ export class ActivateAccountBody {
166
+ @ApiProperty()
167
+ @IsString()
168
+ @IsNotEmpty()
169
+ token: string;
170
+
171
+ @ApiProperty()
172
+ @IsString()
173
+ @IsNotEmpty()
174
+ @MaxLength(PASSWORD_MAX_LENGTH)
175
+ password: string;
176
+ }
177
+
178
+ export interface ReadActivateAccount {
179
+ idUser: number;
180
+ idSociety: number;
181
+ societyName: string;
182
+ idTypeBrand: number;
183
+ /** `bearer <jwt>`, same shape as `POST /authenticate/external/exchange` */
184
+ token: string;
185
+ }
package/ts/types/index.ts CHANGED
@@ -544,6 +544,7 @@ export * from './Enum/UrgencyLevel.js';
544
544
  export * from './Enum/Formalism.js';
545
545
  export * from './Enum/Kyc.js';
546
546
  export * from './Enum/ExternalAuthenticationLinkPurpose.js';
547
+ export * from './Enum/Signup.js';
547
548
 
548
549
  // Interfaces API
549
550
  export * from './Interface/api/accountingTransaction/Create.js';
@@ -1135,6 +1136,7 @@ export * from './Interface/api/config/ConfigType.js';
1135
1136
  export * from './Interface/api/card/Cron.js';
1136
1137
  export * from './Interface/api/user/RegisterProspect.js';
1137
1138
  export * from './Interface/api/user/RegisterWebhook.js';
1139
+ export * from './Interface/api/user/Signup.js';
1138
1140
  export * from './Interface/api/stateBankAccount/Query.js';
1139
1141
  export * from './Interface/api/absenceRequest/QueryAbsenceRequest.js';
1140
1142
  export * from './Interface/api/absenceRequest/QueryCalendarAbsenceRequest.js';
@@ -3,7 +3,9 @@ import { parsePhoneNumberFromString } from 'libphonenumber-js';
3
3
 
4
4
  @ValidatorConstraint({ name: 'isE164Phone', async: false })
5
5
  export class IsE164PhoneNumber implements ValidatorConstraintInterface {
6
- validate(text: string) {
6
+ validate(text: unknown): boolean {
7
+ // class-validator runs every validator of the property: a missing or non-string value must not throw
8
+ if (typeof text !== 'string') return false;
7
9
  const phoneNumber = parsePhoneNumberFromString(text);
8
10
  return isDefined(phoneNumber) && phoneNumber.number === text && phoneNumber.isValid();
9
11
  }