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
@@ -1,38 +1,51 @@
1
1
  import type * as typeNodemailer from 'nodemailer';
2
2
  import type JSONTransport from 'nodemailer/lib/json-transport';
3
- import type Mail from 'nodemailer/lib/mailer';
4
3
  import type SendmailTransport from 'nodemailer/lib/sendmail-transport';
5
4
  import type SESTransport from 'nodemailer/lib/ses-transport';
6
5
  import type SMTPPool from 'nodemailer/lib/smtp-pool';
7
6
  import type SMTPTransport from 'nodemailer/lib/smtp-transport';
8
7
  import type StreamTransport from 'nodemailer/lib/stream-transport';
9
- import type { ComponentProps, ComponentType, SvelteComponent } from 'svelte';
10
- import { Module } from '../../server';
11
- import { default as DefaultMail } from '../templates/DefaultMail.svelte';
12
- export type TransportTypes = SMTPTransport | SMTPPool | SendmailTransport | StreamTransport | JSONTransport | SESTransport | typeNodemailer.Transport<any> | DefaultOptions;
13
- export type DefaultOptions = SMTPTransport.Options | SMTPPool.Options | SendmailTransport.Options | StreamTransport.Options | JSONTransport.Options | SESTransport.Options | typeNodemailer.TransportOptions;
14
- export type MailOptions<ComponentTemplateDefault extends SvelteComponent> = {
15
- from?: Mail.Options['from'];
16
- template?: {
17
- component?: ComponentType<ComponentTemplateDefault>;
18
- brandColor?: string;
8
+ import { Module } from 'remult/server';
9
+ import { type MailStyle } from './formatMailHelper';
10
+ export type TransportTypes = SMTPPool | SMTPPool.Options | SendmailTransport | SendmailTransport.Options | StreamTransport | StreamTransport.Options | JSONTransport | JSONTransport.Options | SESTransport | SESTransport.Options | SMTPTransport | SMTPTransport.Options | string;
11
+ export type DefaultOptions = typeNodemailer.SendMailOptions;
12
+ type GlobalEasyOptions = {
13
+ saveHtml?: boolean;
14
+ from?: DefaultOptions['from'];
15
+ service?: string;
16
+ primaryColor?: string;
17
+ secondaryColor?: string;
18
+ footer?: string;
19
+ toHtml?: (args: MailStyle) => string;
20
+ };
21
+ export type MailOptions = GlobalEasyOptions & {
22
+ nodemailer?: {
23
+ transport?: TransportTypes;
24
+ defaults?: DefaultOptions;
19
25
  };
20
- transport?: TransportTypes;
21
- defaults?: DefaultOptions;
22
- apiUrl?: Parameters<typeof typeNodemailer.createTestAccount>[0];
23
26
  };
24
27
  declare let transporter: ReturnType<typeof typeNodemailer.createTransport>;
25
28
  declare module 'remult' {
26
29
  interface RemultContext {
27
- /** Better checking is it's present or not, that's why it's "?" */
28
30
  sendMail?: SendMail;
29
31
  }
30
32
  }
31
33
  export type SendMail = typeof sendMail;
32
- export declare const sendMail: <ComponentTemplateDefault extends SvelteComponent = DefaultMail>(
34
+ export declare const sendMail: (
33
35
  /** usefull for logs, it has NO impact on the mail itself */
34
- topic: string, mailOptions: Parameters<typeof transporter.sendMail>[0] & {
35
- templateProps?: ComponentProps<ComponentTemplateDefault> | undefined;
36
+ topic: string, easyOptions: GlobalEasyOptions & {
37
+ to: Required<DefaultOptions>['to'];
38
+ subject: Required<DefaultOptions>['subject'];
39
+ title?: string;
40
+ sections: {
41
+ html: string;
42
+ cta?: {
43
+ html: string;
44
+ link: string;
45
+ } | undefined;
46
+ }[];
47
+ }, options?: {
48
+ nodemailer?: MailOptions['nodemailer'];
36
49
  }) => ReturnType<typeof transporter.sendMail>;
37
- export declare const mail: (o?: MailOptions<SvelteComponent>) => Module;
50
+ export declare const mail: (o?: MailOptions) => Module<unknown>;
38
51
  export {};
@@ -1,22 +1,38 @@
1
1
  import nodemailer from 'nodemailer';
2
- import { asClassComponent } from 'svelte/legacy';
3
- import { render } from 'svelty-email';
4
- import { remult } from 'remult';
2
+ import { remult, repo } from 'remult';
3
+ import { Module } from 'remult/server';
5
4
  import { cyan, green, magenta, red, sleep, white } from '@kitql/helpers';
6
- import { Module } from '../../server';
7
- import { default as DefaultMail } from '../templates/DefaultMail.svelte';
5
+ import { log, mailEntities } from '../index';
6
+ import { toHtml } from './formatMailHelper';
8
7
  let transporter;
9
8
  let globalOptions;
10
9
  const initMail = async (o) => {
11
- globalOptions = o;
12
- if (o?.transport) {
13
- transporter = nodemailer.createTransport(o?.transport, o?.defaults);
10
+ globalOptions = {
11
+ ...o,
12
+ nodemailer: {
13
+ ...o?.nodemailer,
14
+ defaults: {
15
+ from: o?.from,
16
+ ...o?.nodemailer?.defaults,
17
+ },
18
+ },
19
+ };
20
+ if (o?.nodemailer?.transport) {
21
+ transporter = nodemailer.createTransport(o?.nodemailer?.transport, o?.nodemailer?.defaults);
14
22
  }
15
23
  else {
16
24
  try {
17
- nodemailer.createTestAccount(globalOptions?.apiUrl ?? '', (err, account) => {
25
+ nodemailer.createTestAccount((err, account) => {
18
26
  if (account) {
19
- globalOptions = { ...globalOptions, from: account.user };
27
+ globalOptions = {
28
+ ...globalOptions,
29
+ ...{
30
+ ...globalOptions?.nodemailer,
31
+ nodemailer: {
32
+ defaults: { from: account.user },
33
+ },
34
+ },
35
+ };
20
36
  transporter = nodemailer.createTransport({
21
37
  host: account.smtp.host,
22
38
  port: account.smtp.port,
@@ -28,16 +44,52 @@ const initMail = async (o) => {
28
44
  });
29
45
  }
30
46
  else {
31
- mailModule.log.error("Error nodemailer.createTestAccount() can't be done.");
47
+ log.error("Error nodemailer.createTestAccount() can't be done.");
32
48
  }
33
49
  });
34
50
  }
35
51
  catch (error) {
36
- mailModule.log.error("Error nodemailer.createTestAccount() can't be done.");
52
+ log.error("Error nodemailer.createTestAccount() can't be done.");
37
53
  }
38
54
  }
39
55
  };
40
- export const sendMail = async (topic, mailOptions) => {
56
+ export const sendMail = async (topic, easyOptions, options) => {
57
+ let { nodemailer: nodemailerOptions } = options ?? {};
58
+ const easyOptionsToUse = {
59
+ ...easyOptions,
60
+ service: easyOptions.service ?? globalOptions?.service,
61
+ primaryColor: easyOptions.primaryColor ?? globalOptions?.primaryColor,
62
+ secondaryColor: easyOptions.secondaryColor ?? globalOptions?.secondaryColor,
63
+ footer: easyOptions.footer ?? globalOptions?.footer,
64
+ from: easyOptions.from ?? globalOptions?.from,
65
+ };
66
+ let { primaryColor, secondaryColor, title, footer, service } = easyOptionsToUse;
67
+ const { subject, sections, to } = easyOptionsToUse;
68
+ service = service ?? 'service';
69
+ primaryColor = primaryColor ?? '#0d0f70';
70
+ secondaryColor = secondaryColor ?? '#653eae';
71
+ title = title ?? subject ?? 'subject';
72
+ footer = footer ?? 'The team wishes you a great day 🚀';
73
+ const metadata = {
74
+ service,
75
+ primaryColor,
76
+ secondaryColor,
77
+ subject,
78
+ title,
79
+ footer,
80
+ sections,
81
+ };
82
+ const html = easyOptionsToUse.toHtml ? easyOptionsToUse.toHtml(metadata) : toHtml(metadata);
83
+ nodemailerOptions = {
84
+ defaults: {
85
+ ...globalOptions?.nodemailer?.defaults,
86
+ to,
87
+ subject,
88
+ html,
89
+ ...nodemailerOptions?.defaults,
90
+ from: easyOptionsToUse.from ?? globalOptions?.from,
91
+ },
92
+ };
41
93
  // if the transporter is not ready, wait for it! (it can happen only if nothing is set...)
42
94
  for (let i = 0; i < 30; i++) {
43
95
  if (transporter !== undefined) {
@@ -46,47 +98,70 @@ export const sendMail = async (topic, mailOptions) => {
46
98
  await sleep(100);
47
99
  }
48
100
  try {
49
- if (!mailOptions.html) {
50
- const template = asClassComponent(globalOptions?.template?.component ?? DefaultMail);
51
- const props = {
52
- brandColor: globalOptions?.template?.brandColor ?? '#5B68DF',
53
- ...mailOptions.templateProps,
54
- };
55
- mailOptions.text = render({ template, props, options: { plainText: true, pretty: true } });
56
- mailOptions.html = render({ template, props, options: { plainText: false, pretty: true } });
57
- }
58
- const info = await transporter.sendMail({
59
- ...mailOptions,
60
- ...{ from: mailOptions.from ?? globalOptions?.from },
61
- });
62
- if (!globalOptions?.transport) {
63
- mailModule.log.error(`${magenta(`[${topic}]`)} - ⚠️ ${red(`mail not configured`)} ⚠️
64
- We are still nice and generated you an email preview link:
65
- 👉 ${cyan(String(nodemailer.getTestMessageUrl(
66
- // @ts-ignore
67
- info)))}
68
-
69
- To really send mails, check out the doc ${white(`https://firstly.fun/modules/mail`)}.
101
+ if (!globalOptions?.nodemailer?.transport) {
102
+ const info = await transporter.sendMail({ ...nodemailerOptions.defaults });
103
+ log.error(`${magenta(`[${topic}]`)} - ⚠️ ${red(`mail not configured`)} ⚠️
104
+ We are still nice and generated you an email preview link (the mail we not really sent):
105
+ 👉 ${cyan(String(nodemailer.getTestMessageUrl(info)))}
106
+
107
+ To really send mails, check out the doc ${white(`https://firstly.fun/modules/mail`)}.
70
108
  `);
109
+ await repo(mailEntities.Mail).insert({
110
+ status: 'transport_not_configured',
111
+ to: JSON.stringify(to),
112
+ html: easyOptionsToUse.saveHtml ? html : '',
113
+ topic,
114
+ metadata,
115
+ });
116
+ return info;
71
117
  }
72
118
  else {
73
- mailModule.log.success(`${magenta(`[${topic}]`)} - Sent to ${typeof mailOptions.to === 'string' ? green(mailOptions.to) : mailOptions.to}`);
119
+ const info = await transporter.sendMail({ ...nodemailerOptions.defaults });
120
+ log.success(`${magenta(`[${topic}]`)} - Sent to ${typeof nodemailerOptions.defaults?.to === 'string' ? green(nodemailerOptions.defaults?.to) : nodemailerOptions.defaults?.to}`);
121
+ await repo(mailEntities.Mail).insert({
122
+ status: 'sent',
123
+ to: JSON.stringify(to),
124
+ html: easyOptionsToUse.saveHtml ? html : '',
125
+ topic,
126
+ metadata,
127
+ });
128
+ return info;
74
129
  }
75
- return info;
76
130
  }
77
131
  catch (error) {
78
- mailModule.log.error(`${magenta(`[${topic}]`)} - Error`, error);
132
+ if (error instanceof Error && error.message.includes('Missing credentials for "PLAIN"')) {
133
+ log.error(`${magenta(`[${topic}]`)} - ⚠️ ${red(`mail not well configured`)} ⚠️
134
+ 👉 transport used:
135
+ ${cyan(JSON.stringify(globalOptions?.nodemailer?.transport, null, 2))}
136
+ `);
137
+ }
138
+ else {
139
+ log.error(`${magenta(`[${topic}]`)} - Error`, error);
140
+ }
141
+ await repo(mailEntities.Mail).insert({
142
+ status: 'error',
143
+ errorInfo: JSON.stringify(error),
144
+ to: JSON.stringify(to),
145
+ html: easyOptionsToUse.saveHtml ? html : '',
146
+ topic,
147
+ metadata,
148
+ });
149
+ throw error;
79
150
  }
80
151
  };
81
152
  const mailModule = new Module({
82
- name: 'mail',
153
+ key: 'mail',
83
154
  priority: -888,
155
+ entities: Object.values(mailEntities),
84
156
  });
85
157
  export const mail = (o) => {
86
158
  mailModule.initApi = () => {
87
159
  initMail(o);
160
+ // Need to init in the 2 places!
161
+ remult.context.sendMail = sendMail;
88
162
  };
89
163
  mailModule.initRequest = async () => {
164
+ // Need to init in the 2 places!
90
165
  remult.context.sendMail = sendMail;
91
166
  };
92
167
  return mailModule;
@@ -1,6 +1,6 @@
1
1
  import type { RequestEvent } from '@sveltejs/kit';
2
2
  import { type ClassType } from 'remult';
3
- import type { RemultServerOptions } from 'remult/server';
3
+ import { type RemultServerOptions } from 'remult/server';
4
4
  import { Log } from '@kitql/helpers';
5
5
  type ModuleInput = {
6
6
  /**
@@ -12,9 +12,10 @@ type ModuleInput = {
12
12
  controllers?: ClassType<any>[];
13
13
  initApi?: RemultServerOptions<RequestEvent>['initApi'];
14
14
  initRequest?: RemultServerOptions<RequestEvent>['initRequest'];
15
- modules?: Module[];
15
+ /** @deprecated use `remult` modules instead */
16
+ modulesFF?: ModuleFF[];
16
17
  };
17
- export declare class Module {
18
+ export declare class ModuleFF {
18
19
  name: string;
19
20
  log: Log;
20
21
  priority?: number;
@@ -22,11 +23,13 @@ export declare class Module {
22
23
  controllers?: ClassType<any>[];
23
24
  initApi?: RemultServerOptions<RequestEvent>['initApi'];
24
25
  initRequest?: RemultServerOptions<RequestEvent>['initRequest'];
25
- modules?: Module[];
26
+ /** @deprecated use `remult` modules instead */
27
+ modulesFF?: ModuleFF[];
26
28
  constructor(input: ModuleInput);
27
29
  }
28
30
  type Options = RemultServerOptions<RequestEvent<Partial<Record<string, string>>, string | null>> & {
29
- modules?: Module[] | undefined;
31
+ /** @deprecated use `remult` modules instead */
32
+ modulesFF?: ModuleFF[] | undefined;
30
33
  };
31
34
  declare module 'remult' {
32
35
  interface RemultContext {
@@ -45,5 +48,5 @@ export declare const firstly: (o: Options) => import("remult/remult-sveltekit").
45
48
  /**
46
49
  * Full flat and ordered list by index and concatenaining the modules name
47
50
  */
48
- export declare const modulesFlatAndOrdered: (modules: Module[]) => Module[];
51
+ export declare const modulesFlatAndOrdered: (modules: ModuleFF[]) => ModuleFF[];
49
52
  export {};
@@ -1,9 +1,9 @@
1
1
  import {} from 'remult';
2
- import { remultSveltekit } from 'remult/remult-sveltekit';
2
+ import { remultApi } from 'remult/remult-sveltekit';
3
+ import { Module } from 'remult/server';
3
4
  import { Log } from '@kitql/helpers';
4
- import { building } from '$app/environment';
5
5
  import { sveltekit } from '../sveltekit/server';
6
- export class Module {
6
+ export class ModuleFF {
7
7
  name;
8
8
  log;
9
9
  priority;
@@ -11,7 +11,8 @@ export class Module {
11
11
  controllers;
12
12
  initApi;
13
13
  initRequest;
14
- modules;
14
+ /** @deprecated use `remult` modules instead */
15
+ modulesFF;
15
16
  constructor(input) {
16
17
  this.name = input.name;
17
18
  this.log = new Log(`firstly | ${this.name}`);
@@ -20,7 +21,7 @@ export class Module {
20
21
  this.controllers = input.controllers;
21
22
  this.initApi = input.initApi;
22
23
  this.initRequest = input.initRequest;
23
- this.modules = input.modules;
24
+ this.modulesFF = input.modulesFF;
24
25
  }
25
26
  }
26
27
  export let entities = [];
@@ -29,18 +30,24 @@ export let entities = [];
29
30
  * @deprecated will be done directly in remult when modules will be in 😉
30
31
  */
31
32
  export const firstly = (o) => {
32
- const modulesSorted = modulesFlatAndOrdered([
33
- ...[...(o.modules ?? []), sveltekit()],
34
- new Module({
35
- name: 'default',
36
- entities: o.entities ?? [],
37
- controllers: o.controllers ?? [],
38
- initRequest: o.initRequest,
39
- initApi: o.initApi,
40
- }),
41
- ]);
42
- entities = modulesSorted.flatMap((m) => m.entities ?? []);
43
- return remultSveltekit({
33
+ const modulesSorted = modulesFlatAndOrdered([...[...(o.modulesFF ?? []), sveltekit()]]);
34
+ const ffModulesToRemult = modulesSorted.map((m) => {
35
+ return new Module({
36
+ key: m.name,
37
+ entities: m.entities ?? [],
38
+ controllers: m.controllers ?? [],
39
+ initApi: m.initApi,
40
+ initRequest: m.initRequest,
41
+ });
42
+ });
43
+ // REMULT P1: With Generate Migrations it's a bit hard to get all entities from all modules.
44
+ entities = [
45
+ ...modulesSorted.flatMap((m) => m.entities ?? []),
46
+ ...(o.entities ?? []),
47
+ //Managing only the first level... should be ok for now...
48
+ ...(o?.modules?.flatMap((m) => m.entities ?? []) ?? []),
49
+ ];
50
+ return remultApi({
44
51
  // Changing the default default of remult
45
52
  logApiEndPoints: false,
46
53
  admin: true,
@@ -56,37 +63,8 @@ export const firstly = (o) => {
56
63
  },
57
64
  // Add user configuration
58
65
  ...o,
59
- // Module part
60
- entities,
61
- controllers: modulesSorted.flatMap((m) => m.controllers ?? []),
62
- initRequest: async (kitEvent, op) => {
63
- for (let i = 0; i < modulesSorted.length; i++) {
64
- const f = modulesSorted[i].initRequest;
65
- if (f) {
66
- try {
67
- await f(kitEvent, op);
68
- }
69
- catch (error) {
70
- modulesSorted[i].log.error(error);
71
- }
72
- }
73
- }
74
- },
75
- initApi: async (r) => {
76
- if (!building) {
77
- for (let i = 0; i < modulesSorted.length; i++) {
78
- const f = modulesSorted[i].initApi;
79
- if (f) {
80
- try {
81
- await f(r);
82
- }
83
- catch (error) {
84
- modulesSorted[i].log.error(error);
85
- }
86
- }
87
- }
88
- }
89
- },
66
+ // native remult modules
67
+ modules: [...(o.modules ?? []), ...ffModulesToRemult],
90
68
  });
91
69
  };
92
70
  /**
@@ -97,9 +75,9 @@ export const modulesFlatAndOrdered = (modules) => {
97
75
  return modules.reduce((acc, module) => {
98
76
  const fullName = parentName ? `${parentName}-${module.name}` : module.name;
99
77
  // Create a new module object without the 'modules' property
100
- const { modules: _, ...flatModule } = module;
78
+ const { modulesFF: _, ...flatModule } = module;
101
79
  const newModule = { ...flatModule, name: fullName };
102
- const subModules = module.modules ? flattenModules(module.modules, fullName) : [];
80
+ const subModules = module.modulesFF ? flattenModules(module.modulesFF, fullName) : [];
103
81
  return [...acc, newModule, ...subModules];
104
82
  }, []);
105
83
  };
@@ -39,14 +39,14 @@
39
39
  onchange={() => (selectedThing = group.key)}
40
40
  aria-label={group.caption}
41
41
  />
42
- <div role="tabpanel" class="tab-content bg-base-100 border-base-300 rounded-box p-6">
42
+ <div role="tabpanel" class="tab-content rounded-box border-base-300 bg-base-100 p-6">
43
43
  <FF_Form {r} groups={[group]} show={{ title: false }}></FF_Form>
44
44
  </div>
45
45
  {/each}
46
46
  </div>
47
47
  {:else if layoutToUse.type === 'accordion'}
48
48
  {#each layoutToUse.groups ?? [] as group (group.key)}
49
- <div class="bg-base-100 collapse">
49
+ <div class="collapse bg-base-100">
50
50
  <input
51
51
  type="radio"
52
52
  name="my-accordion"
@@ -85,10 +85,10 @@
85
85
  <p>Hey 🫵 developer, you are missing a few things 🤡!</p>
86
86
  <p>Or use use one of the custom built in dialog like</p>
87
87
 
88
- <pre class="bg-base-300 mt-2 p-2 text-xs">await dialog.confirmDelete('The Car')</pre>
88
+ <pre class="mt-2 bg-base-300 p-2 text-xs">await dialog.confirmDelete('The Car')</pre>
89
89
 
90
90
  <p>Or pass you own component</p>
91
- <pre class="bg-base-300 mt-2 p-2 text-xs">{`await dialog.show({
91
+ <pre class="mt-2 bg-base-300 p-2 text-xs">{`await dialog.show({
92
92
  detail: { caption: 'Interlocuteur' },
93
93
  component: CreateCarForm,
94
94
  props: { isEdit: false },
@@ -5,6 +5,7 @@ export declare function overwriteOptions<valueType = unknown, entityType = unkno
5
5
  valueType: any;
6
6
  key: entityType extends object ? keyof entityType & string : string;
7
7
  caption: string;
8
+ label: string;
8
9
  dbName: string;
9
10
  inputType: string;
10
11
  allowNull: boolean;
@@ -20,6 +20,7 @@ export { overwriteOptions, deepMerge, isOfType } from './helpers';
20
20
  export { dialog } from './dialog/dialog';
21
21
  export { SP } from './class/SP.svelte';
22
22
  export type { ParamDefinition } from './class/SP.svelte';
23
+ export { initRemultSvelteReactivity } from './initRemultSvelteReactivity';
23
24
  declare module 'remult' {
24
25
  interface FieldOptions<entityType = unknown, valueType = unknown> {
25
26
  ui?: CellMetadata<valueType, entityType>['ui'];
@@ -16,6 +16,7 @@ export { tryCatch, tryCatchSync } from './tryCatch';
16
16
  export { overwriteOptions, deepMerge, isOfType } from './helpers';
17
17
  export { dialog } from './dialog/dialog';
18
18
  export { SP } from './class/SP.svelte';
19
+ export { initRemultSvelteReactivity } from './initRemultSvelteReactivity';
19
20
  // - [ ] Try to pnpm pack to see what css is needed.
20
21
  // - [ ] let's look at the data-ff-xxx story ?
21
22
  // - [ ] how lib defaults should be configured ?
@@ -0,0 +1 @@
1
+ export declare function initRemultSvelteReactivity(): void;
@@ -0,0 +1,29 @@
1
+ import { createSubscriber } from 'svelte/reactivity';
2
+ import { Remult, remult } from 'remult';
3
+ // To be done once in the application.
4
+ export function initRemultSvelteReactivity() {
5
+ // Auth reactivity (remult.user, remult.authenticated(), ...)
6
+ {
7
+ let update = () => { };
8
+ const s = createSubscriber((u) => {
9
+ update = u;
10
+ });
11
+ remult.subscribeAuth({
12
+ reportObserved: () => s(),
13
+ reportChanged: () => update(),
14
+ });
15
+ }
16
+ // Entities reactivity
17
+ {
18
+ Remult.entityRefInit = (x) => {
19
+ let update = () => { };
20
+ const s = createSubscriber((u) => {
21
+ update = u;
22
+ });
23
+ x.subscribe({
24
+ reportObserved: () => s(),
25
+ reportChanged: () => update(),
26
+ });
27
+ };
28
+ }
29
+ }
@@ -1,5 +1,5 @@
1
- import { Module } from '../../server';
1
+ import { ModuleFF } from '../../server';
2
2
  /**
3
3
  * @deprecated will be done directly in remult when modules will be in 😉
4
4
  */
5
- export declare const sveltekit: () => Module;
5
+ export declare const sveltekit: () => ModuleFF;
@@ -1,10 +1,10 @@
1
1
  import { remult } from 'remult';
2
- import { Module } from '../../server';
2
+ import { ModuleFF } from '../../server';
3
3
  /**
4
4
  * @deprecated will be done directly in remult when modules will be in 😉
5
5
  */
6
6
  export const sveltekit = () => {
7
- return new Module({
7
+ return new ModuleFF({
8
8
  name: 'sveltekit',
9
9
  priority: -779,
10
10
  entities: [],
@@ -102,7 +102,7 @@
102
102
  {...$content}
103
103
  use:content
104
104
  transition:fade={{ duration: 100 }}
105
- class="bg-base-300 z-30 rounded-lg ring-1 ring-black"
105
+ class="z-30 rounded-lg bg-base-300 ring-1 ring-black"
106
106
  >
107
107
  <div {...$arrow} use:arrow></div>
108
108
  <div class="px-4 py-1">
@@ -40,6 +40,7 @@
40
40
 
41
41
  export let clearable: boolean | undefined = undefined
42
42
  export let disabled = false
43
+ export let createRequest: ((args: { input: string; id: string }) => void) | undefined = undefined
43
44
 
44
45
  const dispatch = createEventDispatcher()
45
46
 
@@ -246,7 +247,8 @@
246
247
  error = e.detail
247
248
  }}
248
249
  createOptionWhenNoResult={!!cell.field?.options.createOptionWhenNoResult}
249
- on:createRequest
250
+ {createRequest}
251
+ default_select_if_one_item={!!cell.field?.options.default_select_if_one_item}
250
252
  />
251
253
  {/if}
252
254
  {:else if metaType.kind === 'enum'}
@@ -301,7 +303,7 @@
301
303
  {...common(cell.field)}
302
304
  autocomplete="off"
303
305
  class={tw(
304
- `join-item placeholder:text-base-content/30 w-full bg-transparent`,
306
+ `join-item w-full bg-transparent placeholder:text-base-content/30`,
305
307
  metaType.subKind === 'number' && 'text-end',
306
308
  )}
307
309
  type={metaType.subKind.replaceAll('dateOnly', 'date')}
@@ -328,6 +330,6 @@
328
330
  />
329
331
  {:else}
330
332
  <!-- This shoud NEVER be displayed -->
331
- <span class="text-error flex items-center pl-2">Type "{cell.field?.inputType}" not managed!</span>
333
+ <span class="flex items-center pl-2 text-error">Type "{cell.field?.inputType}" not managed!</span>
332
334
  {/if}
333
335
  </FieldContainer>
@@ -12,9 +12,12 @@ declare class __sveltets_Render<T extends Record<any, any>> {
12
12
  focus?: boolean | undefined;
13
13
  clearable?: boolean | undefined | undefined;
14
14
  disabled?: boolean | undefined;
15
+ createRequest?: ((args: {
16
+ input: string;
17
+ id: string;
18
+ }) => void) | undefined;
15
19
  };
16
20
  events(): {
17
- createRequest: CustomEvent<any>;
18
21
  selected: CustomEvent<any>;
19
22
  } & {
20
23
  [evt: string]: CustomEvent<any>;
@@ -17,6 +17,7 @@
17
17
  export let store: StoreItem<T>
18
18
 
19
19
  export let focusKey: string | null | undefined = null
20
+ export let createRequest: ((args: { input: string; id: string }) => void) | undefined = undefined
20
21
 
21
22
  const getError = (errors: any, field: FieldMetadata<any, any>) => {
22
23
  const fo = getRelationFieldInfo(field)
@@ -105,7 +106,7 @@
105
106
  bind:value={$store.item[cell.field.key]}
106
107
  error={getError($store.errors, cell.field)}
107
108
  {focus}
108
- on:createRequest
109
+ {createRequest}
109
110
  />
110
111
  <!-- disabled={isDisableFieldDynamic(cell)} -->
111
112
  {:else}
@@ -7,9 +7,12 @@ declare class __sveltets_Render<T extends Record<any, any>> {
7
7
  cells: Cell<T>[];
8
8
  store: StoreItem<T>;
9
9
  focusKey?: string | null | undefined;
10
+ createRequest?: ((args: {
11
+ input: string;
12
+ id: string;
13
+ }) => void) | undefined;
10
14
  };
11
15
  events(): {
12
- createRequest: CustomEvent<any>;
13
16
  changed: CustomEvent<any>;
14
17
  } & {
15
18
  [evt: string]: CustomEvent<any>;