firstly 0.0.6 → 0.0.8

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 (60) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/esm/FF_Entity.js +20 -4
  3. package/esm/ROUTES.d.ts +11 -11
  4. package/esm/ROUTES.js +5 -5
  5. package/esm/SqlDatabase/FF_LogToConsole.d.ts +4 -1
  6. package/esm/SqlDatabase/FF_LogToConsole.js +15 -8
  7. package/esm/api/index.d.ts +2 -2
  8. package/esm/api/index.js +9 -9
  9. package/esm/auth/Adapter.js +1 -7
  10. package/esm/auth/AuthController.server.d.ts +1 -2
  11. package/esm/auth/AuthController.server.js +96 -65
  12. package/esm/auth/RoleHelpers.d.ts +1 -1
  13. package/esm/auth/RoleHelpers.js +9 -9
  14. package/esm/auth/client/Auth.d.ts +11 -4
  15. package/esm/auth/client/Auth.js +13 -5
  16. package/esm/auth/{Entities.d.ts → client/Entities.d.ts} +3 -3
  17. package/esm/auth/{Entities.js → client/Entities.js} +30 -14
  18. package/esm/auth/client/index.d.ts +5 -0
  19. package/esm/auth/client/index.js +5 -0
  20. package/esm/auth/helper.d.ts +6 -1
  21. package/esm/auth/helper.js +11 -4
  22. package/esm/auth/index.d.ts +9 -11
  23. package/esm/auth/index.js +74 -70
  24. package/esm/auth/providers/github.js +2 -1
  25. package/esm/auth/providers/index.js +1 -1
  26. package/esm/auth/providers/strava.js +2 -1
  27. package/esm/auth/static/assets/{Page-RIbXHuZG.d.ts → Page-BEFYPjis.d.ts} +1 -1
  28. package/esm/auth/static/assets/{Page-RIbXHuZG.js → Page-BEFYPjis.js} +1 -1
  29. package/esm/auth/static/assets/Page-Cfysx_UV.d.ts +6 -0
  30. package/esm/auth/static/assets/Page-Cfysx_UV.js +18 -0
  31. package/esm/auth/static/assets/{Page-DBWJjlEQ.d.ts → Page-DtgkOCJs.d.ts} +1 -1
  32. package/esm/auth/static/assets/{Page-DBWJjlEQ.js → Page-DtgkOCJs.js} +1 -1
  33. package/esm/auth/static/assets/index-QypqCYwC.d.ts +63 -0
  34. package/esm/auth/static/assets/index-QypqCYwC.js +2 -0
  35. package/esm/auth/static/index.html +1 -1
  36. package/esm/auth/types.d.ts +7 -5
  37. package/esm/bin/cmd.js +28 -14
  38. package/esm/cellsBuildor.d.ts +1 -0
  39. package/esm/cellsBuildor.js +24 -12
  40. package/esm/changeLog/index.d.ts +23 -7
  41. package/esm/changeLog/index.js +24 -18
  42. package/esm/feedback/FeedbackController.d.ts +12 -3
  43. package/esm/feedback/FeedbackController.js +62 -11
  44. package/esm/feedback/index.d.ts +1 -0
  45. package/esm/feedback/ui/DialogIssue.svelte +28 -9
  46. package/esm/feedback/ui/DialogIssues.svelte +7 -2
  47. package/esm/handle/index.d.ts +1 -1
  48. package/esm/index.d.ts +4 -2
  49. package/esm/index.js +1 -1
  50. package/esm/mail/index.js +1 -1
  51. package/esm/mail/templates/DefaultMail.svelte +1 -1
  52. package/esm/ui/Field.svelte +2 -10
  53. package/esm/ui/GridPaginate.svelte +7 -7
  54. package/esm/ui/GridPaginate.svelte.d.ts +1 -1
  55. package/esm/vite/index.js +4 -1
  56. package/package.json +8 -8
  57. package/esm/auth/static/assets/Page-apb_xgZT.d.ts +0 -6
  58. package/esm/auth/static/assets/Page-apb_xgZT.js +0 -18
  59. package/esm/auth/static/assets/index-qfq98Nyd.d.ts +0 -63
  60. package/esm/auth/static/assets/index-qfq98Nyd.js +0 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # firstly
2
2
 
3
+ ## 0.0.8
4
+
5
+ ### Patch Changes
6
+
7
+ - [#27](https://github.com/jycouet/firstly/pull/27)
8
+ [`66711b2`](https://github.com/jycouet/firstly/commit/66711b2373c69006d7ae5f06d8f4a6cb0e43670b)
9
+ Thanks [@jycouet](https://github.com/jycouet)! - fix the session creation on signIn! (+default
10
+ expiration is 30 days)
11
+
12
+ - [#27](https://github.com/jycouet/firstly/pull/27)
13
+ [`0657c5c`](https://github.com/jycouet/firstly/commit/0657c5ca8b81673b493a6815a196a8c5351ecdf0)
14
+ Thanks [@jycouet](https://github.com/jycouet)! - add uiStaticPath option in auth module to
15
+ overwrite where are the static files for the module (dev option)
16
+
17
+ ## 0.0.7
18
+
19
+ ### Patch Changes
20
+
21
+ - [#25](https://github.com/jycouet/firstly/pull/25)
22
+ [`54f2f6a`](https://github.com/jycouet/firstly/commit/54f2f6a833c1977c3163e91ce3172fa8edc9da47)
23
+ Thanks [@jycouet](https://github.com/jycouet)! - adding e2e tests for accounts
24
+
25
+ - [#25](https://github.com/jycouet/firstly/pull/25)
26
+ [`943e9d0`](https://github.com/jycouet/firstly/commit/943e9d0b6d5d6a631dc78661d188a76f254d4632)
27
+ Thanks [@jycouet](https://github.com/jycouet)! - rename name to identifier in db
28
+
3
29
  ## 0.0.6
4
30
 
5
31
  ### Patch Changes
package/esm/FF_Entity.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Entity } from 'remult';
2
+ import { recordDeleted, recordSaved } from './changeLog';
2
3
  const toAllow = (permission) => {
3
4
  if (permission) {
4
5
  if (Array.isArray(permission)) {
@@ -16,9 +17,24 @@ export function FF_Entity(key, options) {
16
17
  allowApiInsert: options.allowApiInsert ?? toAllow(options.permissionApiInsert),
17
18
  allowApiRead: options.allowApiRead ?? toAllow(options.permissionApiRead),
18
19
  allowApiUpdate: options.allowApiUpdate ?? toAllow(options.permissionApiUpdate),
19
- // saved: async (item, e) => {
20
- // console.log('was saved')
21
- // await options?.saved?.(item, e)
22
- // },
20
+ // changesLogs
21
+ saved: async (entity, e) => {
22
+ await options?.saved?.(entity, e);
23
+ if (options.changeLog === false) {
24
+ // Don't log changes
25
+ }
26
+ else {
27
+ await recordSaved(entity, e, options.changeLog);
28
+ }
29
+ },
30
+ deleted: async (entity, e) => {
31
+ await options?.deleted?.(entity, e);
32
+ if (options.changeLog === false) {
33
+ // Don't log changes
34
+ }
35
+ else {
36
+ await recordDeleted(entity, e, options.changeLog);
37
+ }
38
+ },
23
39
  });
24
40
  }
package/esm/ROUTES.d.ts CHANGED
@@ -32,16 +32,16 @@ declare const AllObjs: {
32
32
  repo?: (string | number);
33
33
  }) => string;
34
34
  "/": string;
35
+ "/auth": string;
35
36
  "/mail": string;
36
- "/remult": string;
37
- "/remult/auth": string;
38
- "/remult/enum": string;
39
- "/remult/select": string;
40
- "/ui": string;
37
+ "/ui/dialog": string;
38
+ "/ui/enum": string;
39
+ "/ui/fieldGroup": string;
40
+ "/ui/select": string;
41
41
  };
42
42
  type AllTypes = typeof AllObjs;
43
43
  export type Routes = keyof AllTypes extends `${string}/${infer Route}` ? `/${Route}` : keyof AllTypes;
44
- export declare const routes: ("/" | "/mail" | "/remult" | "/remult/auth" | "/remult/enum" | "/remult/select" | "/ui" | "firstly_sign_in" | "remult_admin" | "github")[];
44
+ export declare const routes: ("/" | "/auth" | "/mail" | "/ui/dialog" | "/ui/enum" | "/ui/fieldGroup" | "/ui/select" | "firstly_sign_in" | "remult_admin" | "github")[];
45
45
  /**
46
46
  * To be used like this:
47
47
  * ```ts
@@ -70,12 +70,12 @@ export declare function route<T extends NonFunctionKeys<AllTypes>>(key: T): stri
70
70
  export type KIT_ROUTES = {
71
71
  PAGES: {
72
72
  '/': never;
73
+ '/auth': never;
73
74
  '/mail': never;
74
- '/remult': never;
75
- '/remult/auth': never;
76
- '/remult/enum': never;
77
- '/remult/select': never;
78
- '/ui': never;
75
+ '/ui/dialog': never;
76
+ '/ui/enum': never;
77
+ '/ui/fieldGroup': never;
78
+ '/ui/select': never;
79
79
  };
80
80
  SERVERS: Record<string, never>;
81
81
  ACTIONS: Record<string, never>;
package/esm/ROUTES.js CHANGED
@@ -9,12 +9,12 @@
9
9
  */
10
10
  const PAGES = {
11
11
  "/": `/`,
12
+ "/auth": `/auth`,
12
13
  "/mail": `/mail`,
13
- "/remult": `/remult`,
14
- "/remult/auth": `/remult/auth`,
15
- "/remult/enum": `/remult/enum`,
16
- "/remult/select": `/remult/select`,
17
- "/ui": `/ui`
14
+ "/ui/dialog": `/ui/dialog`,
15
+ "/ui/enum": `/ui/enum`,
16
+ "/ui/fieldGroup": `/ui/fieldGroup`,
17
+ "/ui/select": `/ui/select`
18
18
  };
19
19
  /**
20
20
  * SERVERS
@@ -1 +1,4 @@
1
- export declare const FF_LogToConsole: (duration: number, query: string, args: Record<string, any>, short?: boolean) => string | undefined;
1
+ export declare const FF_LogToConsole: (duration: number, query: string, args: Record<string, any>, options?: {
2
+ withDetails?: boolean;
3
+ tablesToHide?: string[][];
4
+ }) => string | undefined;
@@ -16,7 +16,7 @@ const typeQuery = new Map([
16
16
  ]);
17
17
  const keys = ['FROM', 'WHERE', 'LIMIT', 'OFFSET'];
18
18
  const typeQueryKey = Array.from(typeQuery.keys());
19
- export const FF_LogToConsole = (duration, query, args, short = true) => {
19
+ export const FF_LogToConsole = (duration, query, args, options) => {
20
20
  const rawSql = query
21
21
  .replace(/(\r\n|\n|\r|\t)/gm, ' ')
22
22
  .replace(/ +/g, ' ')
@@ -79,7 +79,10 @@ export const FF_LogToConsole = (duration, query, args, short = true) => {
79
79
  const subTables = uniqueTables.slice(0, -1);
80
80
  const time = ` ${bgCyan((duration * 1000).toFixed(0).padStart(3) + ' ms ')}`;
81
81
  let toLog = '';
82
- if (short) {
82
+ if (options?.withDetails) {
83
+ toLog = `${typeQuery.get(first) || '💢'}` + time + ` ${final_s}`;
84
+ }
85
+ else {
83
86
  toLog =
84
87
  `${typeQuery.get(first) || '💢'}` +
85
88
  `${time}` +
@@ -87,12 +90,16 @@ export const FF_LogToConsole = (duration, query, args, short = true) => {
87
90
  `${listArgs.length > 0 ? ` { ${listArgs.join(', ')} }` : ``}` +
88
91
  `${subTables.length > 0 ? magenta(` (sub: ${subTables.join(', ')})`) : ``}`;
89
92
  }
90
- else {
91
- toLog = `${typeQuery.get(first) || '💢'}` + time + ` ${final_s}`;
92
- }
93
- // Filter out a few things
94
- const filterOutTable = ['"auth_user"', '"auth_user_session"'];
95
- const OnoOfFiltered = tables.length === 1 && filterOutTable.includes(tables[0]);
93
+ const toFilterOut = options?.tablesToHide ?? [
94
+ ['__remult_migrations_version'],
95
+ ['information_Schema.tables'],
96
+ ['information_schema.columns'],
97
+ ['ff_auth.accounts'],
98
+ ['ff_auth.users'],
99
+ ['ff_auth.users_sessions'],
100
+ ['_ff_change_logs'],
101
+ ];
102
+ const OnoOfFiltered = toFilterOut.some((item) => item.every((i) => tables.map((c) => c.replaceAll('"', '')).includes(i)));
96
103
  if (!OnoOfFiltered) {
97
104
  // console.log(`toLogLong`, toLogLong)
98
105
  log.info(toLog);
@@ -1,4 +1,4 @@
1
- /// <reference types=".pnpm/@sveltejs+kit@2.5.24_@sveltejs+vite-plugin-svelte@3.1.1_svelte@4.2.18_vite@5.4.1_@types+node@_vtylvkjv5lewhfcl4vq2py4rce/node_modules/@sveltejs/kit" />
1
+ /// <reference types=".pnpm/@sveltejs+kit@2.5.24_@sveltejs+vite-plugin-svelte@3.1.2_svelte@4.2.18_vite@5.4.1_@types+node@_lnml5jetshdinsnlj53joqxhde/node_modules/@sveltejs/kit" />
2
2
  import { type Handle, type MaybePromise, type RequestEvent } from '@sveltejs/kit';
3
3
  import { type ClassType } from 'remult';
4
4
  import type { RemultServerOptions } from 'remult/server';
@@ -17,7 +17,7 @@ export type Module = {
17
17
  handlePosRemult?: Handle;
18
18
  earlyReturn?: (input: Parameters<Handle>[0]) => MaybePromise<{
19
19
  early: false;
20
- resolve?: never;
20
+ resolve?: undefined;
21
21
  } | {
22
22
  early: true;
23
23
  resolve: ReturnType<Handle>;
package/esm/api/index.js CHANGED
@@ -36,6 +36,15 @@ export const firstly = (o) => {
36
36
  initRequest: async (kitEvent, op) => {
37
37
  // usefull for later...
38
38
  remult.context.url = kitEvent.url;
39
+ remult.context.setHeaders = (headers) => {
40
+ kitEvent.setHeaders(headers);
41
+ };
42
+ remult.context.setCookie = (name, value, opts) => {
43
+ kitEvent.cookies.set(name, value, opts);
44
+ };
45
+ remult.context.deleteCookie = (name, opts) => {
46
+ kitEvent.cookies.delete(name, opts);
47
+ };
39
48
  for (let i = 0; i < modulesSorted.length; i++) {
40
49
  const f = modulesSorted[i].initRequest;
41
50
  if (f) {
@@ -48,15 +57,6 @@ export const firstly = (o) => {
48
57
  }
49
58
  }
50
59
  }
51
- remult.context.setHeaders = (headers) => {
52
- kitEvent.setHeaders(headers);
53
- };
54
- remult.context.setCookie = (name, value, opts) => {
55
- kitEvent.cookies.set(name, value, opts);
56
- };
57
- remult.context.deleteCookie = (name, opts) => {
58
- kitEvent.cookies.delete(name, opts);
59
- };
60
60
  },
61
61
  initApi: async (r) => {
62
62
  if (!building) {
@@ -9,13 +9,7 @@ export class RemultLuciaAdapter {
9
9
  if (user) {
10
10
  return [
11
11
  { ...session, attributes: {} },
12
- {
13
- ...user,
14
- attributes: {
15
- ...user,
16
- session: { id: session.id, expiresAt: session.expiresAt },
17
- },
18
- },
12
+ { ...user, attributes: oSafe.transformDbUserToClientUser(session, user) },
19
13
  ];
20
14
  }
21
15
  }
@@ -10,8 +10,7 @@ export declare class AuthControllerServer {
10
10
  */
11
11
  static signInDemo(name: string): Promise<string>;
12
12
  /**
13
- * This is for login / password authentication SignUp
14
- * _(The first param `name` can be "anything")_
13
+ * This is for login / password authentication invite
15
14
  */
16
15
  static invite(email: string): Promise<"Mail sent !" | "Demo Mail sent !" | "ok">;
17
16
  /**
@@ -3,11 +3,12 @@ import { DEV } from 'esm-env';
3
3
  import { generateId } from 'lucia';
4
4
  import { createDate, TimeSpan } from 'oslo';
5
5
  import { remult } from 'remult';
6
- import { green, yellow } from '@kitql/helpers';
7
- import { AUTH_OPTIONS, getSafeOptions, logAuth, lucia } from '.';
6
+ import { green, magenta, yellow } from '@kitql/helpers';
7
+ import { AUTH_OPTIONS, getSafeOptions, lucia } from '.';
8
8
  import { sendMail } from '../mail';
9
- import { FFAuthProvider } from './Entities.js';
10
- import { createSession } from './helper';
9
+ import { logAuth } from './client';
10
+ import { FFAuthProvider } from './client/Entities.js';
11
+ import { createOrExtendSession } from './helper';
11
12
  import { mergeRoles } from './RoleHelpers';
12
13
  async function getArgon() {
13
14
  const { Argon2id } = await import('oslo/password');
@@ -58,39 +59,55 @@ export class AuthControllerServer {
58
59
  throw new Error(`${name} not found as demo account!`);
59
60
  }
60
61
  const oSafe = getSafeOptions();
61
- let user = await remult.repo(oSafe.User).findFirst({ name });
62
+ let user = await remult.repo(oSafe.User).findFirst({ identifier: name });
62
63
  if (!user) {
63
64
  user = remult.repo(oSafe.User).create();
64
65
  }
65
- user.name = name;
66
+ user.identifier = name;
66
67
  const r = mergeRoles(user.roles, account.roles);
67
68
  user.roles = r.roles;
68
69
  await remult.repo(oSafe.User).save(user);
69
- await createSession(user.id);
70
+ await createOrExtendSession(user.id);
70
71
  return "You're in with demo account!";
71
72
  }
72
73
  /**
73
- * This is for login / password authentication SignUp
74
- * _(The first param `name` can be "anything")_
74
+ * This is for login / password authentication invite
75
75
  */
76
76
  static async invite(email) {
77
77
  const oSafe = getSafeOptions();
78
- const existingUser = await remult.repo(oSafe.User).findOne({ where: { name: email } });
79
- if (existingUser) {
78
+ const existingAccount = await remult.repo(oSafe.Account).findOne({
79
+ where: {
80
+ providerUserId: email,
81
+ provider: FFAuthProvider.PASSWORD.id,
82
+ },
83
+ });
84
+ if (existingAccount) {
80
85
  // throw Error("Already invited !")
81
86
  }
82
87
  else {
83
- const user = await remult.repo(oSafe.User).insert({
84
- name: email,
88
+ const token = generateId(40);
89
+ // TODO: Do we create the user or just the account ?!
90
+ // 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?
91
+ // const user = await remult.repo(oSafe.User).insert({
92
+ // identifier: email,
93
+ // })
94
+ await remult.repo(oSafe.Account).insert({
95
+ provider: FFAuthProvider.PASSWORD.id,
96
+ providerUserId: email,
97
+ // userId: user.id,
98
+ // hashPassword: await passwordHash(password),
99
+ token: token,
100
+ expiresAt: createDate(new TimeSpan(AUTH_OPTIONS.providers?.password?.verifyMailExpiresIn ?? 5 * 60, 's')),
101
+ lastVerifiedAt: undefined,
85
102
  });
86
- const url = `${remult.context.url.origin}`;
103
+ const url = `${remult.context.url.origin}${oSafe.firstlyData.props.ui?.paths.reset_password}?token=${token}`;
87
104
  if (AUTH_OPTIONS?.invitationSend) {
88
105
  await AUTH_OPTIONS?.invitationSend({ email, url });
89
- logAuth.success(`Done with custom ${green('invitationSend')} (${yellow(url)})`);
106
+ logAuth.success(`${green('[custom]')}${magenta('[invitationSend]')} (${yellow(url)})`);
90
107
  return 'Mail sent !';
91
108
  }
92
109
  else {
93
- await sendMail('invite', {
110
+ await sendMail('invitationSend', {
94
111
  to: email,
95
112
  subject: 'Invitation',
96
113
  templateProps: {
@@ -111,7 +128,7 @@ export class AuthControllerServer {
111
128
  ],
112
129
  },
113
130
  });
114
- logAuth.success(`Done with ${green('sendMail')} (${url})`);
131
+ logAuth.success(`${magenta('[invitationSend]')} (${yellow(url)})`);
115
132
  return 'Demo Mail sent !';
116
133
  }
117
134
  }
@@ -129,37 +146,49 @@ export class AuthControllerServer {
129
146
  if (!oSafe.password_enabled) {
130
147
  throw Error('Password is not enabled!');
131
148
  }
132
- const existingUser = await remult.repo(oSafe.User).findOne({ where: { name: email } });
133
- if (existingUser) {
149
+ const existingAccount = await remult.repo(oSafe.Account).findOne({
150
+ where: {
151
+ providerUserId: email,
152
+ provider: FFAuthProvider.PASSWORD.id,
153
+ },
154
+ });
155
+ if (existingAccount) {
134
156
  throw Error("You can't signup twice !");
135
157
  }
136
158
  checkPassword(password);
137
- const user = await remult.repo(oSafe.User).insert({
138
- name: email,
139
- });
140
159
  const token = generateId(40);
141
- await remult.repo(oSafe.Account).insert({
142
- provider: FFAuthProvider.PASSWORD.id,
143
- providerUserId: email,
144
- userId: user.id,
145
- hashPassword: await passwordHash(password),
146
- token: oSafe.verifiedMethod === 'auto' ? undefined : token,
147
- expiresAt: oSafe.verifiedMethod === 'auto'
148
- ? undefined
149
- : createDate(new TimeSpan(AUTH_OPTIONS.providers?.password?.verifyMailExpiresIn ?? 5 * 60, 's')),
150
- lastVerifiedAt: oSafe.verifiedMethod === 'auto' ? new Date() : undefined,
160
+ await remult.dataProvider.transaction(async () => {
161
+ const user = await remult.repo(oSafe.User).insert({
162
+ identifier: email,
163
+ });
164
+ await remult.repo(oSafe.Account).insert({
165
+ provider: FFAuthProvider.PASSWORD.id,
166
+ providerUserId: email,
167
+ userId: user.id,
168
+ hashPassword: await passwordHash(password),
169
+ token: oSafe.verifiedMethod === 'auto' ? undefined : token,
170
+ expiresAt: oSafe.verifiedMethod === 'auto'
171
+ ? undefined
172
+ : createDate(new TimeSpan(AUTH_OPTIONS.providers?.password?.verifyMailExpiresIn ?? 5 * 60, 's')),
173
+ lastVerifiedAt: oSafe.verifiedMethod === 'auto' ? new Date() : undefined,
174
+ });
151
175
  });
152
176
  if (oSafe.verifiedMethod === 'auto') {
153
- await createSession(user.id);
177
+ const user = await remult.repo(oSafe.User).findFirst({
178
+ identifier: email,
179
+ });
180
+ if (user) {
181
+ await createOrExtendSession(user.id);
182
+ }
154
183
  }
155
184
  else {
156
185
  const url = `${remult.context.url.origin}${oSafe.firstlyData.props.ui?.paths.verify_email}?token=${token}`;
157
186
  if (AUTH_OPTIONS.providers?.password?.verifyMailSend) {
158
187
  await AUTH_OPTIONS.providers?.password.verifyMailSend({ email, url });
159
- logAuth.success(`Done with custom ${green('verifyMailSend')} (${yellow(url)})`);
188
+ logAuth.success(`${green('[custom]')}${magenta('[verifyMailSend]')} (${yellow(url)})`);
160
189
  }
161
190
  else {
162
- await sendMail('signUpPassword', {
191
+ await sendMail('verifyMailSend', {
163
192
  to: email,
164
193
  subject: 'Wecome',
165
194
  templateProps: {
@@ -176,7 +205,7 @@ export class AuthControllerServer {
176
205
  ],
177
206
  },
178
207
  });
179
- logAuth.success(`Done with ${green('sendMail')} (${url})`);
208
+ logAuth.success(`${magenta('[verifyMailSend]')} (${yellow(url)})`);
180
209
  }
181
210
  }
182
211
  return 'ok';
@@ -190,14 +219,16 @@ export class AuthControllerServer {
190
219
  if (!oSafe.password_enabled) {
191
220
  throw Error('Password is not enabled!');
192
221
  }
193
- const existingUser = await remult
194
- .repo(oSafe.User)
195
- .findOne({ where: { name: email }, include: { accounts: true } });
196
- const accountPassword = existingUser?.accounts.find((c) => c.provider === FFAuthProvider.PASSWORD.id);
197
- if (accountPassword && existingUser) {
198
- const validPassword = await passwordVerify(accountPassword?.hashPassword ?? '', password ?? '');
222
+ const existingAccount = await remult.repo(oSafe.Account).findOne({
223
+ where: {
224
+ providerUserId: email,
225
+ provider: FFAuthProvider.PASSWORD.id,
226
+ },
227
+ });
228
+ if (existingAccount) {
229
+ const validPassword = await passwordVerify(existingAccount?.hashPassword ?? '', password ?? '');
199
230
  if (validPassword) {
200
- await createSession(existingUser.id);
231
+ await createOrExtendSession(existingAccount.userId);
201
232
  return 'ok';
202
233
  }
203
234
  throw Error('Incorrect username or password');
@@ -212,29 +243,25 @@ export class AuthControllerServer {
212
243
  if (!oSafe.password_enabled) {
213
244
  throw Error('Password is not enabled!');
214
245
  }
215
- const u = await remult.repo(getSafeOptions().User).findFirst({ name: email });
216
- if (u) {
217
- let authAccount = await remult.repo(oSafe.Account).findFirst({
218
- userId: u.id,
219
- });
220
- if (!authAccount) {
221
- authAccount = remult.repo(oSafe.Account).create();
222
- authAccount.userId = u.id;
223
- authAccount.provider = FFAuthProvider.PASSWORD.id;
224
- authAccount.providerUserId = email;
225
- }
246
+ const existingAccount = await remult.repo(oSafe.Account).findOne({
247
+ where: {
248
+ providerUserId: email,
249
+ provider: FFAuthProvider.PASSWORD.id,
250
+ },
251
+ });
252
+ if (existingAccount) {
226
253
  const token = generateId(40);
227
- authAccount.token = token;
228
- authAccount.expiresAt = createDate(new TimeSpan(AUTH_OPTIONS.providers?.password?.resetPasswordExpiresIn ?? 5 * 60, 's'));
229
- await remult.repo(oSafe.Account).save(authAccount);
254
+ existingAccount.token = token;
255
+ existingAccount.expiresAt = createDate(new TimeSpan(AUTH_OPTIONS.providers?.password?.resetPasswordExpiresIn ?? 5 * 60, 's'));
256
+ await remult.repo(oSafe.Account).save(existingAccount);
230
257
  const url = `${remult.context.url.origin}${oSafe.firstlyData.props.ui?.paths.reset_password}?token=${token}`;
231
258
  if (AUTH_OPTIONS.providers?.password?.resetPasswordSend) {
232
259
  await AUTH_OPTIONS.providers?.password.resetPasswordSend({ email, url });
233
- logAuth.success(`Done with custom ${green('resetPasswordSend')} (${yellow(url)})`);
260
+ logAuth.success(`${green('[custom]')}${magenta('[resetPasswordSend]')} (${yellow(url)})`);
234
261
  return 'Mail sent !';
235
262
  }
236
263
  else {
237
- await sendMail('forgotPassword', {
264
+ await sendMail('resetPasswordSend', {
238
265
  to: email,
239
266
  subject: 'Reset your password',
240
267
  templateProps: {
@@ -255,7 +282,7 @@ export class AuthControllerServer {
255
282
  ],
256
283
  },
257
284
  });
258
- logAuth.success(`Done with ${green('sendMail')} (${url})`);
285
+ logAuth.success(`${magenta('[resetPasswordSend]')} (${yellow(url)})`);
259
286
  return 'Demo Mail sent !';
260
287
  }
261
288
  }
@@ -279,6 +306,10 @@ export class AuthControllerServer {
279
306
  throw new Error('token expired');
280
307
  }
281
308
  checkPassword(password);
309
+ if (account.userId === undefined) {
310
+ const user = await remult.repo(oSafe.User).insert({ identifier: account.providerUserId });
311
+ account.userId = user.id;
312
+ }
282
313
  await lucia.invalidateUserSessions(account.userId);
283
314
  // update elements
284
315
  account.hashPassword = await passwordHash(password);
@@ -286,7 +317,7 @@ export class AuthControllerServer {
286
317
  account.expiresAt = undefined;
287
318
  account.lastVerifiedAt = new Date();
288
319
  await remult.repo(oSafe.Account).save(account);
289
- await createSession(account.userId);
320
+ await createOrExtendSession(account.userId);
290
321
  return 'reseted';
291
322
  }
292
323
  /** OTP */
@@ -308,11 +339,11 @@ export class AuthControllerServer {
308
339
  const issuer = AUTH_OPTIONS.providers.otp.issuer ?? 'firstly';
309
340
  const uri = createTOTPKeyURI(issuer, email, secret);
310
341
  const oSafe = getSafeOptions();
311
- let user = await remult.repo(oSafe.User).findFirst({ name: email });
342
+ let user = await remult.repo(oSafe.User).findFirst({ identifier: email });
312
343
  if (!user) {
313
344
  user = remult.repo(oSafe.User).create();
314
345
  }
315
- user.name = email;
346
+ user.identifier = email;
316
347
  user = await remult.repo(oSafe.User).save(user);
317
348
  let account = await remult
318
349
  .repo(oSafe.Account)
@@ -347,7 +378,7 @@ export class AuthControllerServer {
347
378
  }
348
379
  const account = accounts[0];
349
380
  const user = await remult.repo(oSafe.User).findId(account.userId);
350
- if (user?.name !== email) {
381
+ if (user?.identifier !== email) {
351
382
  throw new Error('Invalid otp.');
352
383
  }
353
384
  const { decodeHex } = await import('oslo/encoding');
@@ -363,7 +394,7 @@ export class AuthControllerServer {
363
394
  account.token = undefined;
364
395
  account.expiresAt = undefined;
365
396
  await remult.repo(oSafe.Account).save(account);
366
- await createSession(account.userId);
397
+ await createOrExtendSession(account.userId);
367
398
  return 'verified';
368
399
  }
369
400
  /** OAUTH */
@@ -1,6 +1,6 @@
1
1
  import type { ClassType } from 'remult';
2
2
  import { Log } from '@kitql/helpers';
3
- import { FFAuthUser } from './Entities';
3
+ import { FFAuthUser } from './client/Entities';
4
4
  /**
5
5
  * will merge the roles and remove duplicates
6
6
  * will return a new array & a status if the array was changed
@@ -1,6 +1,6 @@
1
1
  import { repo } from 'remult';
2
2
  import { cyan, green, Log, yellow } from '@kitql/helpers';
3
- import { FFAuthUser } from './Entities';
3
+ import { FFAuthUser } from './client/Entities';
4
4
  /**
5
5
  * will merge the roles and remove duplicates
6
6
  * will return a new array & a status if the array was changed
@@ -17,13 +17,13 @@ export const mergeRoles = (existing, newOnes) => {
17
17
  return { roles: Array.from(result), changed };
18
18
  };
19
19
  export const initRoleFromEnv = async (log, userEntity, envValue, role) => {
20
- const names = envValue === undefined ? [] : (envValue ?? '').split(',').map((c) => c.trim());
21
- for (let i = 0; i < names.length; i++) {
22
- const name = names[i].trim();
23
- if (name !== '') {
24
- let user = await repo(userEntity).findFirst({ name });
20
+ const identifiers = envValue === undefined ? [] : (envValue ?? '').split(',').map((c) => c.trim());
21
+ for (let i = 0; i < identifiers.length; i++) {
22
+ const identifier = identifiers[i].trim();
23
+ if (identifier !== '') {
24
+ let user = await repo(userEntity).findFirst({ identifier });
25
25
  if (!user) {
26
- user = repo(userEntity).create({ name, roles: [role] });
26
+ user = repo(userEntity).create({ identifier, roles: [role] });
27
27
  await repo(userEntity).save(user);
28
28
  }
29
29
  else {
@@ -34,8 +34,8 @@ export const initRoleFromEnv = async (log, userEntity, envValue, role) => {
34
34
  }
35
35
  }
36
36
  }
37
- if (names.length > 0) {
38
- log.info(`${cyan(role)}: ${names.map((c) => green(c.trim())).join(', ')} added via ${yellow(`.env`)}.`);
37
+ if (identifiers.length > 0) {
38
+ log.info(`${cyan(role)}: ${identifiers.map((c) => green(c.trim())).join(', ')} added via ${yellow(`.env`)}.`);
39
39
  }
40
40
  else {
41
41
  log.info(`${cyan(role)}: No users added via ${yellow(`.env`)}.`);
@@ -1,14 +1,24 @@
1
1
  import type { AuthorizationURLOptions } from '..';
2
2
  export declare class Auth {
3
+ /** DO NOT USE */
3
4
  static signOutFn: any;
5
+ /** DO NOT USE */
4
6
  static signInDemoFn: any;
7
+ /** DO NOT USE */
5
8
  static inviteFn: any;
9
+ /** DO NOT USE */
6
10
  static signUpPasswordFn: any;
11
+ /** DO NOT USE */
7
12
  static signInPasswordFn: any;
13
+ /** DO NOT USE */
8
14
  static forgotPasswordFn: any;
15
+ /** DO NOT USE */
9
16
  static resetPasswordFn: any;
17
+ /** DO NOT USE */
10
18
  static signInOTPFn: any;
19
+ /** DO NOT USE */
11
20
  static verifyOtpFn: any;
21
+ /** DO NOT USE */
12
22
  static signInOAuthGetUrlFn: any;
13
23
  /**
14
24
  * Sign out the current user
@@ -20,18 +30,15 @@ export declare class Auth {
20
30
  */
21
31
  static signInDemo(name: string): Promise<any>;
22
32
  /**
23
- * This is for login / password authentication SignUp
24
- * _(The first param `name` can be "anything")_
33
+ * This is for login / password authentication Invite someone
25
34
  */
26
35
  static invite(email: string): Promise<any>;
27
36
  /**
28
37
  * This is for login / password authentication SignUp
29
- * _(The first param `email` can be "anything")_
30
38
  */
31
39
  static signUpPassword(email: string, password: string): Promise<any>;
32
40
  /**
33
41
  * This is for login / password authentication SignIn
34
- * _(The first param `email` can be "anything")_
35
42
  */
36
43
  static signInPassword(email: string, password: string): Promise<any>;
37
44
  /**