firstly 0.0.16-next.2 → 0.1.0-next.3

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.
Files changed (105) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/esm/FF_Entity.d.ts +1 -1
  3. package/esm/FF_Entity.js +9 -9
  4. package/esm/ROUTES.d.ts +1 -1
  5. package/esm/ROUTES.js +2 -2
  6. package/esm/SqlDatabase/FF_LogToConsole.d.ts +14 -0
  7. package/esm/SqlDatabase/FF_LogToConsole.js +24 -5
  8. package/esm/auth/Entities.d.ts +2 -1
  9. package/esm/auth/Entities.js +18 -14
  10. package/esm/auth/server/AuthController.server.js +86 -93
  11. package/esm/auth/server/handleAuth.d.ts +4 -2
  12. package/esm/auth/server/handleAuth.js +8 -4
  13. package/esm/auth/server/helperRole.d.ts +11 -4
  14. package/esm/auth/server/helperRole.js +29 -20
  15. package/esm/auth/server/index.d.ts +1 -0
  16. package/esm/auth/server/index.js +1 -0
  17. package/esm/auth/server/module.d.ts +27 -5
  18. package/esm/auth/server/module.js +24 -10
  19. package/esm/auth/server/providers/github.js +13 -2
  20. package/esm/auth/static/assets/Page-BHW08QWz.css +1 -0
  21. package/esm/auth/static/assets/{Page-BorYIfy9.d.ts → Page-CTZPxniP.d.ts} +2 -2
  22. package/esm/auth/static/assets/Page-CTZPxniP.js +1 -0
  23. package/esm/auth/static/assets/{Page-CqsLm8yQ.d.ts → Page-D0d9iZO-.d.ts} +2 -2
  24. package/esm/auth/static/assets/{Page-CqsLm8yQ.js → Page-D0d9iZO-.js} +1 -1
  25. package/esm/auth/static/assets/{Page-Cm4MsdIa.d.ts → Page-DXshwJi7.d.ts} +2 -2
  26. package/esm/auth/static/assets/Page-DXshwJi7.js +20 -0
  27. package/esm/auth/static/assets/{index-Borxa2ns.d.ts → index-LRDptjak.d.ts} +3 -20
  28. package/esm/auth/static/assets/{index-Borxa2ns.js → index-LRDptjak.js} +2 -2
  29. package/esm/auth/static/index.html +1 -1
  30. package/esm/auth/types.d.ts +1 -0
  31. package/esm/bin/cmd.js +16 -16
  32. package/esm/changeLog/changeLogEntities.d.ts +21 -0
  33. package/esm/changeLog/changeLogEntities.js +57 -0
  34. package/esm/changeLog/index.d.ts +3 -15
  35. package/esm/changeLog/index.js +3 -51
  36. package/esm/changeLog/server/index.d.ts +39 -28
  37. package/esm/changeLog/server/index.js +40 -29
  38. package/esm/cron/Cron.d.ts +11 -0
  39. package/esm/cron/Cron.js +43 -0
  40. package/esm/cron/Role_Cron.d.ts +3 -0
  41. package/esm/cron/Role_Cron.js +3 -0
  42. package/esm/cron/index.d.ts +3 -0
  43. package/esm/cron/index.js +3 -0
  44. package/esm/cron/server/index.d.ts +29 -11
  45. package/esm/cron/server/index.js +29 -13
  46. package/esm/feedback/FeedbackController.d.ts +3 -1
  47. package/esm/feedback/FeedbackController.js +23 -1
  48. package/esm/feedback/server/index.d.ts +2 -2
  49. package/esm/feedback/server/index.js +2 -2
  50. package/esm/feedback/types.d.ts +6 -0
  51. package/esm/feedback/ui/DialogIssue.svelte +8 -1
  52. package/esm/feedback/ui/DialogIssues.svelte +1 -1
  53. package/esm/formats/index.d.ts +1 -1
  54. package/esm/formats/index.js +1 -1
  55. package/esm/formats/strings.d.ts +2 -0
  56. package/esm/formats/strings.js +22 -0
  57. package/esm/index.d.ts +1 -2
  58. package/esm/index.js +0 -2
  59. package/esm/mail/Mail.d.ts +13 -0
  60. package/esm/mail/Mail.js +51 -0
  61. package/esm/mail/Role_Mail.d.ts +3 -0
  62. package/esm/mail/Role_Mail.js +3 -0
  63. package/esm/mail/index.d.ts +7 -2
  64. package/esm/mail/index.js +7 -2
  65. package/esm/mail/server/formatMailHelper.d.ts +16 -0
  66. package/esm/mail/server/formatMailHelper.js +113 -0
  67. package/esm/mail/server/index.d.ts +32 -19
  68. package/esm/mail/server/index.js +113 -38
  69. package/esm/server/index.d.ts +9 -6
  70. package/esm/server/index.js +28 -50
  71. package/esm/svelte/FF_Layout.svelte +2 -2
  72. package/esm/svelte/dialog/DialogManagement.svelte +2 -2
  73. package/esm/svelte/helpers.d.ts +1 -0
  74. package/esm/svelte/index.d.ts +1 -0
  75. package/esm/svelte/index.js +1 -0
  76. package/esm/svelte/initRemultSvelteReactivity.d.ts +1 -0
  77. package/esm/svelte/initRemultSvelteReactivity.js +29 -0
  78. package/esm/sveltekit/server/index.d.ts +2 -2
  79. package/esm/sveltekit/server/index.js +2 -2
  80. package/esm/ui/Button.svelte +1 -1
  81. package/esm/ui/Field.svelte +5 -3
  82. package/esm/ui/Field.svelte.d.ts +4 -1
  83. package/esm/ui/FieldGroup.svelte +2 -1
  84. package/esm/ui/FieldGroup.svelte.d.ts +4 -1
  85. package/esm/ui/GridPaginate.svelte +2 -2
  86. package/esm/ui/GridPaginate2.svelte +1 -1
  87. package/esm/ui/Loading.svelte +1 -1
  88. package/esm/ui/Tooltip.svelte +1 -1
  89. package/esm/ui/dialog/DialogForm.svelte +3 -3
  90. package/esm/ui/dialog/DialogManagement.svelte +2 -2
  91. package/esm/ui/dialog/DialogPrimitive.svelte +2 -2
  92. package/esm/ui/dialog/FormEditAction.svelte +2 -2
  93. package/esm/ui/internals/FieldContainer.svelte +2 -2
  94. package/esm/ui/internals/Textarea.svelte +2 -2
  95. package/esm/ui/internals/select/MultiSelectMelt.svelte +6 -6
  96. package/esm/ui/internals/select/SelectMelt.svelte +28 -14
  97. package/esm/ui/internals/select/SelectMelt.svelte.d.ts +4 -1
  98. package/esm/ui/link/LinkPlus.svelte +2 -2
  99. package/esm/vite/index.js +50 -52
  100. package/package.json +15 -12
  101. package/esm/auth/static/assets/Page-BorYIfy9.js +0 -1
  102. package/esm/auth/static/assets/Page-Cm4MsdIa.js +0 -20
  103. package/esm/auth/static/assets/Page-JfNiCSIG.css +0 -1
  104. package/esm/mail/templates/DefaultMail.svelte +0 -86
  105. package/esm/mail/templates/DefaultMail.svelte.d.ts +0 -30
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # firstly
2
2
 
3
+ ## 0.1.0-next.3
4
+
5
+ ### Minor Changes
6
+
7
+ - [#140](https://github.com/jycouet/firstly/pull/140)
8
+ [`94b2188`](https://github.com/jycouet/firstly/commit/94b2188c78772f94e7835ab933fcebbe2a37703c)
9
+ Thanks [@jycouet](https://github.com/jycouet)! - [BREAKING] - deprecate firstly module in favor of
10
+ remult module
11
+
12
+ ```diff
13
+ remultApi({
14
+ -- modules: [], // firstly modules
15
+ ++ modulesFF: [], // firstly modules
16
+ })
17
+
18
+ Then, you can use `modules` level of `remult`
19
+ ```
20
+
21
+ ### Patch Changes
22
+
23
+ - [#117](https://github.com/jycouet/firstly/pull/117)
24
+ [`407ed4d`](https://github.com/jycouet/firstly/commit/407ed4db8f4b99f234932965b870d51f6a9c07ca)
25
+ Thanks [@jycouet](https://github.com/jycouet)! - need to pass `redirect` to handleAuth manually
26
+
27
+ - [#117](https://github.com/jycouet/firstly/pull/117)
28
+ [`f30c737`](https://github.com/jycouet/firstly/commit/f30c73781d8f50da08fcdc25f1f7611133ea8b0c)
29
+ Thanks [@jycouet](https://github.com/jycouet)! - switch mail engine to sailkit
30
+
31
+ - [#117](https://github.com/jycouet/firstly/pull/117)
32
+ [`5e1d67e`](https://github.com/jycouet/firstly/commit/5e1d67eb8f75127c3d729945e20b22c40184ee20)
33
+ Thanks [@jycouet](https://github.com/jycouet)! - [BREAKING] - Auth Identifier got removed in favor
34
+ of name in User table.
35
+
3
36
  ## 0.0.16-next.2
4
37
 
5
38
  ### Patch Changes
@@ -1,2 +1,2 @@
1
1
  import { type EntityOptions } from 'remult';
2
- export declare function FF_Entity<entityType>(key: string, options: EntityOptions<entityType extends new (...args: any) => any ? InstanceType<entityType> : entityType>): (target: any, info?: import("remult/src/remult3/remult3").ClassDecoratorContextStub<entityType extends infer T ? T extends entityType ? T extends new (...args: any) => any ? entityType : never : never : never> | undefined) => any;
2
+ export declare function FF_Entity<entityType>(key: string, options?: EntityOptions<entityType extends new (...args: any) => any ? InstanceType<entityType> : entityType>): (target: any, info?: import("remult/src/remult3/remult3").ClassDecoratorContextStub<entityType extends infer T ? T extends entityType ? T extends new (...args: any) => any ? entityType : never : never : never> | undefined) => any;
package/esm/FF_Entity.js CHANGED
@@ -12,31 +12,31 @@ const toAllow = (permission) => {
12
12
  export function FF_Entity(key, options) {
13
13
  return Entity(key, {
14
14
  ...options,
15
- allowApiCrud: options.allowApiCrud ?? toAllow(options.permissionApiCrud),
16
- allowApiDelete: options.allowApiDelete ?? toAllow(options.permissionApiDelete),
17
- allowApiInsert: options.allowApiInsert ?? toAllow(options.permissionApiInsert),
18
- allowApiRead: options.allowApiRead ?? toAllow(options.permissionApiRead),
19
- allowApiUpdate: options.allowApiUpdate ?? toAllow(options.permissionApiUpdate),
15
+ allowApiCrud: options?.allowApiCrud ?? toAllow(options?.permissionApiCrud),
16
+ allowApiDelete: options?.allowApiDelete ?? toAllow(options?.permissionApiDelete),
17
+ allowApiInsert: options?.allowApiInsert ?? toAllow(options?.permissionApiInsert),
18
+ allowApiRead: options?.allowApiRead ?? toAllow(options?.permissionApiRead),
19
+ allowApiUpdate: options?.allowApiUpdate ?? toAllow(options?.permissionApiUpdate),
20
20
  // changesLogs
21
21
  saved: async (entity, e) => {
22
22
  await options?.saved?.(entity, e);
23
- if (options.changeLog === false) {
23
+ if (options?.changeLog === false) {
24
24
  // Don't log changes
25
25
  }
26
26
  else {
27
27
  if (isBackend()) {
28
- await recordSaved(entity, e, options.changeLog);
28
+ await recordSaved(entity, e, options?.changeLog);
29
29
  }
30
30
  }
31
31
  },
32
32
  deleted: async (entity, e) => {
33
33
  await options?.deleted?.(entity, e);
34
- if (options.changeLog === false) {
34
+ if (options?.changeLog === false) {
35
35
  // Don't log changes
36
36
  }
37
37
  else {
38
38
  if (isBackend()) {
39
- await recordDeleted(entity, e, options.changeLog);
39
+ await recordDeleted(entity, e, options?.changeLog);
40
40
  }
41
41
  }
42
42
  },
package/esm/ROUTES.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * >> DO NOT EDIT THIS FILE MANUALLY <<
5
5
  */
6
- type ParamValue = string | number | undefined;
6
+ type ParamValue = string | number | boolean | null | undefined;
7
7
  /**
8
8
  * Append search params to a string
9
9
  */
package/esm/ROUTES.js CHANGED
@@ -37,8 +37,8 @@ const LINKS = {
37
37
  "remult_admin": `/api/admin`,
38
38
  "github": (params) => {
39
39
  params = params ?? {};
40
- params['owner'] = params['owner'] ?? "jycouet";
41
- params['repo'] = params['repo'] ?? "firstly";
40
+ params['owner'] = params['owner'] ?? "\"jycouet\"";
41
+ params['repo'] = params['repo'] ?? "\"firstly\"";
42
42
  return `https://github.com/${params['owner']}/${params['repo']}`;
43
43
  }
44
44
  };
@@ -1,5 +1,19 @@
1
+ type TypeQuery = 'INSERT' | 'SELECT' | 'SELECT_COUNT' | 'UPDATE' | 'DELETE' | 'CREATE' | 'ALTER' | 'DROP' | 'TRUNCATE' | 'GRANT' | 'REVOKE';
2
+ /**
3
+ * @example
4
+ * SqlDatabase.LogToConsole = (...a) => FF_LogToConsole(...a, {
5
+ * type: {
6
+ * exclude: ['SELECT', 'SELECT_COUNT']
7
+ * }
8
+ * })
9
+ */
1
10
  export declare const FF_LogToConsole: (duration: number, query: string, args: Record<string, any>, options?: {
11
+ type?: {
12
+ include?: TypeQuery[];
13
+ exclude?: TypeQuery[];
14
+ };
2
15
  withDetails?: boolean;
3
16
  tablesToHide?: string[][];
4
17
  ending?: (duration: number, query: string, args: Record<string, any>, tables: string[]) => void;
5
18
  }) => string | undefined;
19
+ export {};
@@ -4,7 +4,7 @@ const typeQuery = new Map([
4
4
  // CRUD
5
5
  ['INSERT', '⚪'], // Used to insert new data into a database.
6
6
  ['SELECT', '🔵'], // Used to select data from a database and retrieve it.
7
- ['COUNT ', '🟦'], // Used to count data from a database and retrieve it.
7
+ ['SELECT_COUNT', '🟦'], // Used to count data from a database and retrieve it.
8
8
  ['UPDATE', '🟣'], // Used to update existing data within a database.
9
9
  ['DELETE', '🟤'], // Used to delete existing data from a database.
10
10
  // Additional
@@ -18,17 +18,36 @@ const typeQuery = new Map([
18
18
  const keys = ['FROM', 'WHERE', 'LIMIT', 'OFFSET'];
19
19
  const typeQueryKey = Array.from(typeQuery.keys());
20
20
  const log = new Log('');
21
+ /**
22
+ * @example
23
+ * SqlDatabase.LogToConsole = (...a) => FF_LogToConsole(...a, {
24
+ * type: {
25
+ * exclude: ['SELECT', 'SELECT_COUNT']
26
+ * }
27
+ * })
28
+ */
21
29
  export const FF_LogToConsole = (duration, query, args, options) => {
22
30
  if (duration < SqlDatabase.durationThreshold)
23
31
  return;
24
32
  const rawSql = query
33
+ .replace(/--.*?(?=\r\n|\n|$)/g, '') // Remove SQL comments
25
34
  .replace(/(\r\n|\n|\r|\t)/gm, ' ')
26
35
  .replace(/ +/g, ' ')
27
36
  .trim();
28
37
  const s = rawSql.split(' ');
29
38
  let first = s[0].toUpperCase();
30
- if (s.includes('count(*)')) {
31
- first = 'COUNT ';
39
+ if (s.length > 1 && s[1].toLowerCase() === 'count(*)') {
40
+ first = 'SELECT_COUNT';
41
+ }
42
+ if (options?.type?.include) {
43
+ if (!options.type.include.includes(first)) {
44
+ return;
45
+ }
46
+ }
47
+ if (options?.type?.exclude) {
48
+ if (options.type.exclude.includes(first)) {
49
+ return;
50
+ }
32
51
  }
33
52
  const tables = [];
34
53
  const listArgs = [];
@@ -75,8 +94,8 @@ export const FF_LogToConsole = (duration, query, args, options) => {
75
94
  ['information_Schema.tables'],
76
95
  ['information_schema.columns'],
77
96
  // ['__remult_migrations_version'],
78
- ['ff_auth.accounts'],
79
- ['ff_auth.users'],
97
+ // ['ff_auth.accounts'],
98
+ // ['ff_auth.users'],
80
99
  ['ff_auth.users_sessions'],
81
100
  ['_ff_change_logs'],
82
101
  ];
@@ -10,7 +10,7 @@ export declare class FFAuthUser {
10
10
  id: string;
11
11
  createdAt: Date;
12
12
  updatedAt?: Date;
13
- identifier: string;
13
+ name: string;
14
14
  roles: string[];
15
15
  accounts: FFAuthAccount[];
16
16
  sessions: FFAuthUserSession[];
@@ -23,6 +23,7 @@ export declare class FFAuthAccount {
23
23
  user: FFAuthUser;
24
24
  provider: string;
25
25
  providerUserId: string;
26
+ email?: string | null;
26
27
  hashPassword?: string;
27
28
  token?: string;
28
29
  expiresAt?: Date;
@@ -15,7 +15,7 @@ let FFAuthUser = class FFAuthUser {
15
15
  id;
16
16
  createdAt;
17
17
  updatedAt;
18
- identifier;
18
+ name;
19
19
  roles = [];
20
20
  accounts;
21
21
  sessions;
@@ -24,29 +24,29 @@ __decorate([
24
24
  Fields.cuid()
25
25
  ], FFAuthUser.prototype, "id", void 0);
26
26
  __decorate([
27
- Fields.createdAt()
27
+ Fields.createdAt({ includeInApi: [FF_Role_Auth.FF_Role_Auth_Admin, FF_Role.FF_Role_Admin] })
28
28
  ], FFAuthUser.prototype, "createdAt", void 0);
29
29
  __decorate([
30
- Fields.updatedAt()
30
+ Fields.updatedAt({ includeInApi: [FF_Role_Auth.FF_Role_Auth_Admin, FF_Role.FF_Role_Admin] })
31
31
  ], FFAuthUser.prototype, "updatedAt", void 0);
32
32
  __decorate([
33
33
  Fields.string({
34
- allowApiUpdate: false,
35
- validate: [
36
- Validators.unique(),
37
- Validators.required(),
38
- (e) => {
39
- if (e.identifier?.length < 2)
40
- throw 'Must be at least 2 characters long';
41
- },
42
- ],
34
+ required: true,
35
+ validate: [Validators.unique(), Validators.required()],
43
36
  })
44
- ], FFAuthUser.prototype, "identifier", void 0);
37
+ ], FFAuthUser.prototype, "name", void 0);
45
38
  __decorate([
46
39
  Fields.json(() => [], {
40
+ includeInApi: [FF_Role_Auth.FF_Role_Auth_Admin, FF_Role.FF_Role_Admin],
47
41
  inputType: 'selectEnum',
48
42
  valueConverter: {
49
- toDb: (x) => (x ? x.join(',') : []),
43
+ toDb: (x) => {
44
+ if (x === null)
45
+ return null;
46
+ if (Array.isArray(x))
47
+ return x.join(',');
48
+ return x;
49
+ },
50
50
  //FIXME: refacto this + remove "permissions" & add a disable user!
51
51
  fromDb: (x) => {
52
52
  return x
@@ -80,6 +80,7 @@ let FFAuthAccount = class FFAuthAccount {
80
80
  user;
81
81
  provider = FFAuthProvider.PASSWORD.id;
82
82
  providerUserId = '';
83
+ email = null;
83
84
  hashPassword;
84
85
  token;
85
86
  expiresAt;
@@ -107,6 +108,9 @@ __decorate([
107
108
  __decorate([
108
109
  Fields.string()
109
110
  ], FFAuthAccount.prototype, "providerUserId", void 0);
111
+ __decorate([
112
+ Fields.string({ allowNull: true })
113
+ ], FFAuthAccount.prototype, "email", void 0);
110
114
  __decorate([
111
115
  Fields.string({ includeInApi: false, allowNull: true })
112
116
  ], FFAuthAccount.prototype, "hashPassword", void 0);
@@ -2,6 +2,7 @@ import { decodeHex, encodeHexLowerCase } from '@oslojs/encoding';
2
2
  import { createTOTPKeyURI, generateTOTP, verifyTOTPWithGracePeriod } from '@oslojs/otp';
3
3
  import { generateState } from 'arctic';
4
4
  import { EntityError, remult, repo } from 'remult';
5
+ import { nameify } from '../../formats/strings.js';
5
6
  import { gray, green, magenta, red, yellow } from '@kitql/helpers';
6
7
  import { FFAuthProvider } from '../Entities.js';
7
8
  import { invalidateSession } from './helperDb.js';
@@ -15,7 +16,7 @@ const getSendMail = () => {
15
16
  authModuleRaw.log.error(`Missing ${green(`remult.context`)}.${red(`sendMail`)}`);
16
17
  authModuleRaw.log.error('');
17
18
  authModuleRaw.log.error(gray('Add this to your modules:'));
18
- authModuleRaw.log.error('import { mail } from "firstly/mail/server"');
19
+ authModuleRaw.log.error('import { mail } from "../../mail/server"');
19
20
  authModuleRaw.log.error('');
20
21
  authModuleRaw.log.error('{');
21
22
  authModuleRaw.log.error(` modules: [`);
@@ -52,19 +53,24 @@ export class AuthControllerServer {
52
53
  if (accounts.length === 0) {
53
54
  throw new EntityError({ message: `Demo accounts are not enabled!` });
54
55
  }
55
- const account = accounts.find((a) => a.name === name);
56
- if (!account) {
56
+ const accountConf = accounts.find((a) => a.name === name);
57
+ if (!accountConf) {
57
58
  throw new EntityError({ message: `${name} not found as demo account!` });
58
59
  }
59
60
  const oSafe = getSafeOptions();
60
- let user = await repo(oSafe.User).findFirst({ identifier: name });
61
- if (!user) {
62
- user = repo(oSafe.User).create();
61
+ const user = await repo(oSafe.User).upsert({ where: { name } });
62
+ await repo(oSafe.Account).upsert({
63
+ where: {
64
+ provider: FFAuthProvider.DEMO.id,
65
+ providerUserId: name,
66
+ userId: user.id,
67
+ },
68
+ });
69
+ const r = mergeRoles(user.roles, accountConf.roles);
70
+ if (r.changed) {
71
+ user.roles = r.roles;
72
+ await repo(oSafe.User).save(user);
63
73
  }
64
- user.identifier = name;
65
- const r = mergeRoles(user.roles, account.roles);
66
- user.roles = r.roles;
67
- await repo(oSafe.User).save(user);
68
74
  const session = await ff_createSession(user.id);
69
75
  return {
70
76
  message: `You're in with demo account!`,
@@ -75,7 +81,7 @@ export class AuthControllerServer {
75
81
  * This is for login / password authentication invite
76
82
  */
77
83
  static async invite(emailParam) {
78
- const email = emailParam.toLowerCase();
84
+ const email = emailParam?.toLowerCase();
79
85
  const oSafe = getSafeOptions();
80
86
  const existingAccount = await repo(oSafe.Account).findOne({
81
87
  where: {
@@ -88,17 +94,11 @@ export class AuthControllerServer {
88
94
  }
89
95
  else {
90
96
  const token = generateAndEncodeToken();
91
- // TODO: Do we create the user or just the account ?!
92
- // TODO 2: Invite is by mail... But the invitee can log with another provider... So what do we do?! maybe not checking the provider... and updating?
93
- // const user = await repo(oSafe.User).insert({
94
- // identifier: email,
95
- // })
96
97
  await repo(oSafe.Account).insert({
97
98
  provider: FFAuthProvider.PASSWORD.id,
98
99
  providerUserId: email,
99
- // userId: user.id,
100
- // hashPassword: await passwordHash(password),
101
- token: token,
100
+ email,
101
+ token,
102
102
  expiresAt: createDate(AUTH_OPTIONS.providers?.password?.mail?.verify?.expiresIn ?? 5 * 60),
103
103
  lastVerifiedAt: undefined,
104
104
  });
@@ -116,23 +116,19 @@ export class AuthControllerServer {
116
116
  await sendMail('invitationSend', {
117
117
  to: email,
118
118
  subject: 'Invitation',
119
- templateProps: {
120
- title: 'Invitation 👋',
121
- previewText: 'This is the mail you were waiting for',
122
- sections: [
123
- {
124
- text: 'Today is your lucky day !',
125
- highlighted: true,
119
+ title: 'Invitation 👋',
120
+ sections: [
121
+ {
122
+ html: 'Today is your lucky day !',
123
+ },
124
+ {
125
+ html: 'You were invited to join the team',
126
+ cta: {
127
+ html: 'JOIN',
128
+ link: url,
126
129
  },
127
- {
128
- text: 'You were invited to join the team',
129
- cta: {
130
- text: 'JOIN',
131
- link: url,
132
- },
133
- },
134
- ],
135
- },
130
+ },
131
+ ],
136
132
  });
137
133
  authModuleRaw.log.success(`${magenta('[invitationSend]')} (${yellow(url)})`);
138
134
  return {
@@ -158,7 +154,7 @@ export class AuthControllerServer {
158
154
  if (!oSafe.password.enabled) {
159
155
  throw new EntityError({ message: 'Password is not enabled!' });
160
156
  }
161
- const email = emailParam.toLowerCase();
157
+ const email = emailParam?.toLowerCase();
162
158
  oSafe.password.validateInput({ identifier: email, password });
163
159
  const existingAccount = await repo(oSafe.Account).findOne({
164
160
  where: {
@@ -173,11 +169,12 @@ export class AuthControllerServer {
173
169
  // REMULT: Do not put it in a transaction, as it will be called from a backendmethod that is already in a transaction! And nested transactions not allowed.
174
170
  // await remult.dataProvider.transaction(async () => {
175
171
  const user = await repo(oSafe.User).insert({
176
- identifier: email,
172
+ name: nameify(email),
177
173
  });
178
174
  await repo(oSafe.Account).insert({
179
175
  provider: FFAuthProvider.PASSWORD.id,
180
176
  providerUserId: email,
177
+ email,
181
178
  userId: user.id,
182
179
  hashPassword: await oSafe.password.hash(password),
183
180
  token: oSafe.verifiedMethod === 'auto' ? undefined : token,
@@ -188,9 +185,6 @@ export class AuthControllerServer {
188
185
  });
189
186
  // })
190
187
  if (oSafe.verifiedMethod === 'auto') {
191
- const user = await repo(oSafe.User).findFirst({
192
- identifier: email,
193
- });
194
188
  if (user) {
195
189
  const session = await ff_createSession(user.id);
196
190
  return {
@@ -210,19 +204,16 @@ export class AuthControllerServer {
210
204
  await sendMail('verifyMailSend', {
211
205
  to: email,
212
206
  subject: 'Wecome',
213
- templateProps: {
214
- title: 'Wecome 👋',
215
- previewText: 'This is the mail you were waiting for',
216
- sections: [
217
- {
218
- text: 'You can validate your account',
219
- cta: {
220
- text: 'HERE',
221
- link: url,
222
- },
207
+ title: 'Wecome 👋',
208
+ sections: [
209
+ {
210
+ html: 'You can validate your account',
211
+ cta: {
212
+ html: 'HERE',
213
+ link: url,
223
214
  },
224
- ],
225
- },
215
+ },
216
+ ],
226
217
  });
227
218
  authModuleRaw.log.success(`${magenta('[verifyMailSend]')} (${yellow(url)})`);
228
219
  }
@@ -241,7 +232,7 @@ export class AuthControllerServer {
241
232
  * _(The first param `email` can be "anything")_
242
233
  */
243
234
  static async signInPassword(emailParam, password) {
244
- const email = emailParam.toLowerCase();
235
+ const email = emailParam?.toLowerCase();
245
236
  const oSafe = getSafeOptions();
246
237
  oSafe.password.validateInput({ identifier: email, password });
247
238
  if (!oSafe.password.enabled) {
@@ -258,22 +249,26 @@ export class AuthControllerServer {
258
249
  if (validPassword) {
259
250
  const session = await ff_createSession(existingAccount.userId);
260
251
  const user = await repo(oSafe.User).findId(existingAccount.userId);
252
+ if (!user) {
253
+ authModuleRaw.log.error('User not found for this arround:', existingAccount);
254
+ throw new EntityError({ message: 'User not found, please contact support.' });
255
+ }
261
256
  return {
262
- message: 'ok',
257
+ message: 'Signing in progress...',
263
258
  user: oSafe.transformDbUserToClientUser(session, user),
264
259
  };
265
260
  }
266
- authModuleRaw.log.error({ email, passwordLength: password.length });
261
+ authModuleRaw.log.error({ email, passwordLengthInfo: password.length });
267
262
  throw new EntityError({ message: 'Incorrect username or password' });
268
263
  }
269
- authModuleRaw.log.error({ email, passwordLength: password.length });
264
+ authModuleRaw.log.error({ email, passwordLengthInfo: password.length });
270
265
  throw new EntityError({ message: 'Incorrect username or password.' });
271
266
  }
272
267
  /**
273
268
  * Forgot your password ? Send a mail to reset it.
274
269
  */
275
270
  static async forgotPassword(emailParam) {
276
- const email = emailParam.toLowerCase();
271
+ const email = emailParam?.toLowerCase();
277
272
  const oSafe = getSafeOptions();
278
273
  if (!oSafe.password.enabled) {
279
274
  throw new EntityError({ message: 'Password is not enabled!' });
@@ -303,32 +298,30 @@ export class AuthControllerServer {
303
298
  await sendMail('resetPasswordSend', {
304
299
  to: email,
305
300
  subject: 'Reset your password',
306
- templateProps: {
307
- title: 'Reset your password 👋',
308
- previewText: 'This is the mail you were waiting for',
309
- sections: [
310
- {
311
- text: 'Did you forgot something ?',
312
- highlighted: true,
313
- },
314
- {
315
- text: 'No worries, you can reset your password',
316
- cta: {
317
- text: 'HERE',
318
- link: url,
319
- },
301
+ sections: [
302
+ {
303
+ html: 'Did you forgot something ?',
304
+ },
305
+ {
306
+ html: 'No worries, you can reset your password',
307
+ cta: {
308
+ html: 'HERE',
309
+ link: url,
320
310
  },
321
- ],
322
- },
311
+ },
312
+ ],
323
313
  });
324
314
  authModuleRaw.log.success(`${magenta('[resetPasswordSend]')} (${yellow(url)})`);
325
315
  return {
326
- message: `Demo | ${oSafe.strings.resetPasswordSend}`,
316
+ message: `${oSafe.strings.resetPasswordSend} (DEMO)`,
327
317
  user: remult.user,
328
318
  };
329
319
  }
330
320
  }
331
- throw new EntityError({ message: oSafe.strings.anErrorOccurred });
321
+ return {
322
+ message: oSafe.strings.resetPasswordUnknownUser,
323
+ user: remult.user,
324
+ };
332
325
  }
333
326
  /**
334
327
  * Reset your password with a token
@@ -349,7 +342,7 @@ export class AuthControllerServer {
349
342
  throw new EntityError({ message: 'token expired' });
350
343
  }
351
344
  if (account.userId === undefined) {
352
- const user = await repo(oSafe.User).insert({ identifier: account.providerUserId });
345
+ const user = await repo(oSafe.User).insert({ name: nameify(account.providerUserId) });
353
346
  account.userId = user.id;
354
347
  }
355
348
  await invalidateSession(account.userId);
@@ -367,7 +360,7 @@ export class AuthControllerServer {
367
360
  }
368
361
  /** OTP */
369
362
  static async signInOTP(emailParam) {
370
- const email = emailParam.toLowerCase();
363
+ const email = emailParam?.toLowerCase();
371
364
  const oSafe = getSafeOptions();
372
365
  if (!oSafe.otp.enabled) {
373
366
  throw new EntityError({ message: `OPT is not enabled!` });
@@ -381,20 +374,16 @@ export class AuthControllerServer {
381
374
  const issuer = AUTH_OPTIONS.providers.otp.issuer ?? 'firstly';
382
375
  const uri = createTOTPKeyURI(issuer, email, key, intervalInSeconds, digits);
383
376
  const oSafe = getSafeOptions();
384
- let user = await repo(oSafe.User).findFirst({ identifier: email });
385
- if (!user) {
386
- user = repo(oSafe.User).create();
387
- }
388
- user.identifier = email;
389
- user = await repo(oSafe.User).save(user);
390
- let account = await remult
391
- .repo(oSafe.Account)
392
- .findFirst({ userId: user.id, provider: FFAuthProvider.OTP.id });
393
- if (!account) {
394
- account = repo(oSafe.Account).create();
377
+ const account = await repo(oSafe.Account).upsert({
378
+ where: {
379
+ provider: FFAuthProvider.OTP.id,
380
+ providerUserId: email,
381
+ },
382
+ });
383
+ if (account.userId === '' || account.userId === undefined) {
384
+ const user = await repo(oSafe.User).insert({ name: nameify(email) });
385
+ account.userId = user.id;
395
386
  }
396
- account.userId = user.id;
397
- account.provider = FFAuthProvider.OTP.id;
398
387
  account.token = otp;
399
388
  account.hashPassword = keyEncoded;
400
389
  await repo(oSafe.Account).save(account);
@@ -417,7 +406,7 @@ export class AuthControllerServer {
417
406
  * Verify the OTP code
418
407
  */
419
408
  static async verifyOtp(emailParam, otp) {
420
- const email = emailParam.toLowerCase();
409
+ const email = emailParam?.toLowerCase();
421
410
  const oSafe = getSafeOptions();
422
411
  if (!oSafe.otp.enabled) {
423
412
  throw new EntityError({ message: `OPT is not enabled!` });
@@ -429,8 +418,7 @@ export class AuthControllerServer {
429
418
  throw new EntityError({ message: 'Invalid otp' });
430
419
  }
431
420
  const account = accounts[0];
432
- const user = await repo(oSafe.User).findId(account.userId);
433
- if (user?.identifier !== email) {
421
+ if (account?.providerUserId !== email) {
434
422
  throw new EntityError({ message: 'Invalid otp.' });
435
423
  }
436
424
  const intervalInSeconds = oSafe.providers?.otp?.expiresIn ?? 30;
@@ -447,6 +435,11 @@ export class AuthControllerServer {
447
435
  account.expiresAt = undefined;
448
436
  await repo(oSafe.Account).save(account);
449
437
  const session = await ff_createSession(account.userId);
438
+ const user = await repo(oSafe.User).findId(account.userId);
439
+ if (!user) {
440
+ authModuleRaw.log.error('User not found for this arround:', account);
441
+ throw new EntityError({ message: 'User not found, please contact support.' });
442
+ }
450
443
  return {
451
444
  message: 'verified',
452
445
  user: oSafe.transformDbUserToClientUser(session, user),
@@ -1,2 +1,4 @@
1
- import { type Handle } from '@sveltejs/kit';
2
- export declare const handleAuth: Handle;
1
+ import { redirect as redirectKit, type Handle } from '@sveltejs/kit';
2
+ export declare const handleAuth: ({ redirect }: {
3
+ redirect: typeof redirectKit;
4
+ }) => Handle;