firstly 0.0.12 → 0.0.14

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 (120) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/esm/ROUTES.d.ts +2 -0
  3. package/esm/ROUTES.js +1 -0
  4. package/esm/api/index.d.ts +9 -0
  5. package/esm/api/index.js +3 -1
  6. package/esm/auth/AuthController.d.ts +12 -23
  7. package/esm/auth/AuthController.js +12 -31
  8. package/esm/auth/server/AuthController.server.d.ts +11 -11
  9. package/esm/auth/server/AuthController.server.js +99 -34
  10. package/esm/auth/server/handleGuard.d.ts +16 -0
  11. package/esm/auth/server/handleGuard.js +67 -0
  12. package/esm/auth/server/helperFirstly.d.ts +1 -1
  13. package/esm/auth/server/helperFirstly.js +1 -0
  14. package/esm/auth/server/index.d.ts +3 -1
  15. package/esm/auth/server/index.js +3 -1
  16. package/esm/auth/server/module.d.ts +105 -89
  17. package/esm/auth/server/module.js +55 -42
  18. package/esm/auth/server/providers/github.d.ts +4 -2
  19. package/esm/auth/server/providers/github.js +2 -2
  20. package/esm/auth/static/assets/Page-B0XXxe0N.d.ts +6 -0
  21. package/esm/auth/static/assets/Page-B0XXxe0N.js +1 -0
  22. package/esm/auth/static/assets/Page-DdKMiUZn.d.ts +6 -0
  23. package/esm/auth/static/assets/Page-DdKMiUZn.js +20 -0
  24. package/esm/auth/static/assets/Page-UV_hqY7I.d.ts +6 -0
  25. package/esm/auth/static/assets/Page-UV_hqY7I.js +1 -0
  26. package/esm/auth/static/assets/Page-mK42zGEw.css +1 -0
  27. package/esm/auth/static/assets/index-C9jzxOBu.d.ts +151 -0
  28. package/esm/auth/static/assets/index-C9jzxOBu.js +42 -0
  29. package/esm/auth/static/assets/index-DKWpA6v7.css +4 -0
  30. package/esm/auth/static/index.html +11 -11
  31. package/esm/auth/types.d.ts +26 -3
  32. package/esm/bin/cmd.js +423 -152
  33. package/esm/cellsBuildor.js +1 -1
  34. package/esm/common.d.ts +5 -0
  35. package/esm/common.js +8 -0
  36. package/esm/cron/server/index.js +1 -1
  37. package/esm/feedback/FeedbackController.js +58 -53
  38. package/esm/feedback/server/index.d.ts +6 -15
  39. package/esm/feedback/server/index.js +4 -5
  40. package/esm/feedback/types.d.ts +14 -0
  41. package/esm/feedback/types.js +4 -0
  42. package/esm/feedback/ui/DialogIssue.svelte +131 -119
  43. package/esm/feedback/ui/DialogIssue.svelte.d.ts +20 -18
  44. package/esm/feedback/ui/DialogIssues.svelte +108 -99
  45. package/esm/feedback/ui/DialogIssues.svelte.d.ts +20 -18
  46. package/esm/feedback/ui/DialogMilestones.svelte +40 -34
  47. package/esm/feedback/ui/DialogMilestones.svelte.d.ts +18 -16
  48. package/esm/feedback/ui/Feedback.svelte +11 -9
  49. package/esm/feedback/ui/Feedback.svelte.d.ts +16 -14
  50. package/esm/index.d.ts +2 -5
  51. package/esm/index.js +2 -8
  52. package/esm/mail/server/index.d.ts +9 -2
  53. package/esm/mail/server/index.js +3 -1
  54. package/esm/mail/templates/DefaultMail.svelte +81 -61
  55. package/esm/mail/templates/DefaultMail.svelte.d.ts +28 -26
  56. package/esm/server/index.d.ts +0 -0
  57. package/esm/server/index.js +1 -0
  58. package/esm/storeItem.d.ts +1 -4
  59. package/esm/storeItem.js +1 -1
  60. package/esm/storeList.d.ts +1 -4
  61. package/esm/sveltekit/server/index.d.ts +3 -9
  62. package/esm/sveltekit/server/index.js +3 -0
  63. package/esm/ui/Button.svelte +112 -89
  64. package/esm/ui/Button.svelte.d.ts +34 -24
  65. package/esm/ui/Clipboardable.svelte +24 -17
  66. package/esm/ui/Clipboardable.svelte.d.ts +34 -23
  67. package/esm/ui/Field.svelte +328 -285
  68. package/esm/ui/Field.svelte.d.ts +15 -8
  69. package/esm/ui/FieldGroup.svelte +112 -91
  70. package/esm/ui/FieldGroup.svelte.d.ts +17 -6
  71. package/esm/ui/Grid.svelte +322 -308
  72. package/esm/ui/Grid.svelte.d.ts +17 -6
  73. package/esm/ui/GridLoading.svelte +28 -27
  74. package/esm/ui/GridLoading.svelte.d.ts +19 -17
  75. package/esm/ui/GridPaginate.svelte +68 -61
  76. package/esm/ui/GridPaginate.svelte.d.ts +21 -19
  77. package/esm/ui/Icon.svelte +116 -80
  78. package/esm/ui/Icon.svelte.d.ts +52 -43
  79. package/esm/ui/Loading.svelte +10 -8
  80. package/esm/ui/Loading.svelte.d.ts +29 -18
  81. package/esm/ui/Tooltip.svelte +38 -35
  82. package/esm/ui/Tooltip.svelte.d.ts +30 -20
  83. package/esm/ui/dialog/DialogForm.svelte +70 -63
  84. package/esm/ui/dialog/DialogForm.svelte.d.ts +18 -16
  85. package/esm/ui/dialog/DialogManagement.svelte +74 -74
  86. package/esm/ui/dialog/DialogManagement.svelte.d.ts +22 -21
  87. package/esm/ui/dialog/DialogPrimitive.svelte +82 -76
  88. package/esm/ui/dialog/DialogPrimitive.svelte.d.ts +35 -25
  89. package/esm/ui/dialog/FormEditAction.svelte +58 -50
  90. package/esm/ui/dialog/FormEditAction.svelte.d.ts +13 -6
  91. package/esm/ui/dialog/dialog.d.ts +1 -4
  92. package/esm/ui/internals/FieldContainer.svelte +24 -17
  93. package/esm/ui/internals/FieldContainer.svelte.d.ts +37 -28
  94. package/esm/ui/internals/Input.svelte +136 -102
  95. package/esm/ui/internals/Input.svelte.d.ts +34 -32
  96. package/esm/ui/internals/Textarea.svelte +60 -52
  97. package/esm/ui/internals/Textarea.svelte.d.ts +31 -28
  98. package/esm/ui/internals/select/MultiSelectMelt.svelte +243 -199
  99. package/esm/ui/internals/select/MultiSelectMelt.svelte.d.ts +29 -27
  100. package/esm/ui/internals/select/SelectMelt.svelte +254 -219
  101. package/esm/ui/internals/select/SelectMelt.svelte.d.ts +34 -32
  102. package/esm/ui/internals/select/SelectRadio.svelte +39 -33
  103. package/esm/ui/internals/select/SelectRadio.svelte.d.ts +24 -22
  104. package/esm/ui/link/Link.svelte +25 -20
  105. package/esm/ui/link/Link.svelte.d.ts +31 -23
  106. package/esm/ui/link/LinkPlus.svelte +52 -51
  107. package/esm/ui/link/LinkPlus.svelte.d.ts +20 -18
  108. package/esm/vite/index.d.ts +2 -3
  109. package/esm/vite/index.js +33 -26
  110. package/package.json +16 -20
  111. package/esm/auth/static/assets/Page-Bb8bFlrP.d.ts +0 -4
  112. package/esm/auth/static/assets/Page-Bb8bFlrP.js +0 -1
  113. package/esm/auth/static/assets/Page-BxomFlZ8.d.ts +0 -4
  114. package/esm/auth/static/assets/Page-BxomFlZ8.js +0 -1
  115. package/esm/auth/static/assets/Page-CaIYu0-y.d.ts +0 -6
  116. package/esm/auth/static/assets/Page-CaIYu0-y.js +0 -19
  117. package/esm/auth/static/assets/Page-MkYglNtu.css +0 -1
  118. package/esm/auth/static/assets/index-Bl0Bk5u0.d.ts +0 -64
  119. package/esm/auth/static/assets/index-Bl0Bk5u0.js +0 -2
  120. package/esm/auth/static/assets/index-R27C_TlP.css +0 -4
package/esm/bin/cmd.js CHANGED
@@ -3,8 +3,10 @@ import { bold, cyan, gray, green, italic, Log } from '@kitql/helpers';
3
3
  import { read, write } from '@kitql/internals';
4
4
  // Need this trick to be be replaced by the real lib alias here ;)
5
5
  const libAlias = '$' + 'lib';
6
+ const serverAlias = '$' + 'server';
7
+ const modulesAlias = '$' + 'modules';
6
8
  const pkgFirstly = JSON.parse(read('./node_modules/firstly/package.json') ?? '{}');
7
- const versionFirstly = pkgFirstly?.peerDependencies?.['remult'] ?? 'latest';
9
+ const versionOfRemult = pkgFirstly?.peerDependencies?.['remult'] ?? 'latest';
8
10
  const pkg = JSON.parse(read('./package.json') ?? '{}');
9
11
  const version = pkg.devDependencies?.['firstly'] ?? pkg.dependencies?.['firstly'] ?? '???';
10
12
  console.info('');
@@ -47,14 +49,12 @@ function mergeAndSort(deps, depsToAdd) {
47
49
  return sorted;
48
50
  }
49
51
  pkg.devDependencies = mergeAndSort(pkg.devDependencies, {
50
- '@kitql/eslint-config': '0.3.7',
51
- '@kitql/helpers': '0.8.10',
52
+ '@kitql/eslint-config': '0.5.8',
53
+ '@kitql/helpers': '0.8.12',
52
54
  pg: '8.12.0',
53
- remult: versionFirstly,
54
- });
55
- pkg.dependencies = mergeAndSort(pkg.dependencies, {
56
- oslo: '^1.2.1',
55
+ remult: versionOfRemult,
57
56
  });
57
+ pkg.dependencies = mergeAndSort(pkg.dependencies, {});
58
58
  pkg.scripts = {
59
59
  ...pkg.scripts,
60
60
  '//// ---- BEST PRACTICES ---- ////': '',
@@ -65,14 +65,48 @@ if (res.includes('all') || res.includes('dependencies')) {
65
65
  write('./package.json', [JSON.stringify(pkg, null, 2)]);
66
66
  }
67
67
  const obj = {
68
- './.eslintrc.cjs': [
69
- `module.exports = {
70
- extends: ['@kitql'],
71
- rules: {
72
- // Your overrides here
73
- }
74
- }
75
- `,
68
+ // Configs
69
+ './.npmrc': [
70
+ `engine-strict=true
71
+
72
+ public-hoist-pattern[]=*eslint*
73
+ public-hoist-pattern[]=*prettier*
74
+ public-hoist-pattern[]=*globals*
75
+ `,
76
+ ],
77
+ './.gitignore': [
78
+ `node_modules
79
+
80
+ # Output
81
+ /.svelte-kit
82
+ /build
83
+
84
+ # Env
85
+ .env
86
+ .env.*
87
+ !.env.example
88
+ !.env.test
89
+
90
+ # Vite
91
+ vite.config.js.timestamp-*
92
+ vite.config.ts.timestamp-*
93
+
94
+ # Firstly / Remult
95
+ /db
96
+ `,
97
+ ],
98
+ './eslint.config.js': [
99
+ `import { kitql } from '@kitql/eslint-config'
100
+
101
+ /** @type { import("eslint").Linter.Config[] } */
102
+ export default [
103
+ ...kitql({ pnpmCatalogs: { enable: false } }),
104
+ {
105
+ name: 'APP:ignores',
106
+ ignores: ['**/*.svelte.ts'],
107
+ },
108
+ ]
109
+ `,
76
110
  ],
77
111
  './.prettierignore': [
78
112
  `node_modules/
@@ -96,16 +130,14 @@ db/
96
130
  src/lib/ROUTES.ts
97
131
  `,
98
132
  ],
99
- './.prettierrc.cjs': [
100
- `const {
101
- //plugins,
102
- ...prettierConfig
103
- } = require('@kitql/eslint-config/.prettierrc.cjs')
104
-
105
- module.exports = {
106
- ...prettierConfig,
133
+ './.prettierrc.mjs': [
134
+ `import { kitql } from '@kitql/eslint-config/.prettierrc.mjs'
135
+
136
+ export default {
137
+ ...kitql(),
107
138
  // Your overrides here
108
- }`,
139
+ }
140
+ `,
109
141
  ],
110
142
  '.env.example': [
111
143
  `# Enable some roles
@@ -117,26 +149,114 @@ module.exports = {
117
149
  # GITHUB_CLIENT_SECRET = ''
118
150
  `,
119
151
  ],
120
- './src/lib/firstly/index.ts': [
121
- `import { FF_Role } from 'firstly'
122
- import { firstly } from 'firstly/api'
123
- import { auth } from 'firstly/auth'
124
- import { changeLog } from 'firstly/changeLog'
125
- import { Log } from '@kitql/helpers'
152
+ './tsconfig.json': [
153
+ `{
154
+ "extends": "./.svelte-kit/tsconfig.json",
155
+ "compilerOptions": {
156
+ "experimentalDecorators": true,
157
+ "allowJs": true,
158
+ "checkJs": true,
159
+ "esModuleInterop": true,
160
+ "forceConsistentCasingInFileNames": true,
161
+ "resolveJsonModule": true,
162
+ "skipLibCheck": true,
163
+ "sourceMap": true,
164
+ "strict": true,
165
+ "moduleResolution": "bundler"
166
+ }
167
+ // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
168
+ //
169
+ // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
170
+ // from the referenced tsconfig.json - TypeScript does not merge them in
171
+ }
172
+ `,
173
+ ],
174
+ './vite.config.ts': [
175
+ `import { sveltekit } from '@sveltejs/kit/vite'
176
+ import { defineConfig } from 'vite'
126
177
 
127
- import { task } from './modules/task'
178
+ import { firstly } from 'firstly/vite'
128
179
 
129
- /**
130
- * Your roles, use them in your app !
131
- */
132
- export const Role = {
133
- Boss: 'Boss',
180
+ import type { KIT_ROUTES } from '${libAlias}/ROUTES'
181
+
182
+ export default defineConfig({
183
+ plugins: [
184
+ // @ts-ignore JYC TODO (vite 5 / vite 6...)
185
+ firstly<KIT_ROUTES>({
186
+ kitRoutes: {
187
+ LINKS: {
188
+ login: 'ff/auth/sign-in',
189
+ github: 'https://github.com/[owner]/[repo]',
190
+ remult_admin: 'api/admin',
191
+ },
192
+ }
193
+ }),
194
+ sveltekit(),
195
+ ],
196
+ })
197
+ `,
198
+ ],
199
+ './svelte.config.js': [
200
+ `import adapter from '@sveltejs/adapter-auto'
201
+ import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
202
+
203
+ /** @type {import('@sveltejs/kit').Config} */
204
+ const config = {
205
+ // Consult https://svelte.dev/docs/kit/integrations
206
+ // for more information about preprocessors
207
+ preprocess: vitePreprocess(),
208
+
209
+ kit: {
210
+ // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
211
+ // If your environment is not supported, or you settled on a specific environment, switch out the adapter.
212
+ // See https://svelte.dev/docs/kit/adapters for more information about adapters.
213
+ adapter: adapter(),
214
+ alias: {
215
+ $modules: './src/modules',
216
+ $server: './src/server',
217
+ },
218
+ },
134
219
  }
135
220
 
136
- /**
137
- * Your logs with a nice prefix, use \`log.info("Hello")\` / \`log.success("Yeah")\` / \`log.error("Ho nooo!")\` and see !
138
- */
139
- export const log = new Log('${pkg.name}')
221
+ export default config
222
+ `,
223
+ ],
224
+ // App files
225
+ './src/app.d.ts': [
226
+ `// See https://svelte.dev/docs/kit/types#app.d.ts
227
+ // for information about these interfaces
228
+ declare global {
229
+ namespace App {
230
+ // interface Error {}
231
+ // interface Locals {}
232
+ // interface PageData {}
233
+ // interface PageState {}
234
+ // interface Platform {}
235
+ }
236
+ }
237
+
238
+ declare module 'remult' {
239
+ export interface UserInfo {
240
+ // Your custom user info
241
+ }
242
+
243
+ export interface FieldOptions<entityType, valueType> {
244
+ placeholder?: string
245
+ }
246
+ }
247
+
248
+ export { }
249
+ `,
250
+ ],
251
+ './src/server/index.ts': [
252
+ `import { FF_Role } from 'firstly'
253
+ import { firstly, Module } from 'firstly/api'
254
+ import { auth } from 'firstly/auth/server'
255
+ import { mail } from 'firstly/mail/server'
256
+ import { changeLog } from 'firstly/changeLog/server'
257
+
258
+ import { log, Role } from '${libAlias}'
259
+ import { task } from '${modulesAlias}/task/server'
140
260
 
141
261
  export const api = firstly({
142
262
  //----------------------------------------
@@ -157,8 +277,8 @@ export const api = firstly({
157
277
  providers: {
158
278
  demo: [
159
279
  { name: 'Ermin' },
160
- { name: 'JYC', roles: [FF_Role.Admin] },
161
- { name: 'Noam', roles: [FF_Role.Admin, Role.Boss] },
280
+ { name: 'JYC', roles: [FF_Role.FF_Role_Admin] },
281
+ { name: 'Noam', roles: [FF_Role.FF_Role_Admin, Role.Boss] },
162
282
  ],
163
283
 
164
284
  // password: {},
@@ -170,13 +290,20 @@ export const api = firstly({
170
290
  // To enable OAuth via Github
171
291
  // Instructions by hovering the method \`github\`
172
292
  // NEEDS ON TOP OF THE FILE:
173
- // import { github } from 'firstly/auth/providers'
293
+ // import { github } from 'firstly/auth/server'
174
294
  //----------------------------------------
175
295
  // github(),
176
296
  ],
177
297
  },
178
298
  }),
179
299
 
300
+ //----------------------------------------
301
+ // Core Module: mail
302
+ //----------------------------------------
303
+ mail({
304
+ // options
305
+ }),
306
+
180
307
  //----------------------------------------
181
308
  // example of a userland module
182
309
  //----------------------------------------
@@ -185,14 +312,14 @@ export const api = firstly({
185
312
  //----------------------------------------
186
313
  // example of a userland inline module
187
314
  //----------------------------------------
188
- {
315
+ new Module({
189
316
  name: 'app',
190
317
  entities: [],
191
318
  controllers: [],
192
319
  initApi: async () => {
193
320
  log.success('App is ready! 🚀')
194
321
  },
195
- },
322
+ }),
196
323
 
197
324
  //----------------------------------------
198
325
  // Replace @Entity by @FF_Entity in your entities to enable changeLog on this entity
@@ -204,21 +331,34 @@ export const api = firstly({
204
331
  ],
205
332
  './src/hooks.server.ts': [
206
333
  `import { sequence } from '@sveltejs/kit/hooks'
207
-
208
- import { firstly } from 'firstly/handle'
209
-
210
- import { api } from '${libAlias}/firstly'
211
-
212
- export const handle = sequence(firstly(api))
334
+ import { redirect } from '@sveltejs/kit'
335
+
336
+ import { handleAuth, handleGuard } from 'firstly/auth/server'
337
+ import { route } from '${libAlias}/ROUTES'
338
+ import { api as handleRemult } from '${serverAlias}'
339
+
340
+ export const handle = sequence(
341
+ //
342
+ handleRemult,
343
+ handleAuth,
344
+ // client side guard is not here!
345
+ handleGuard({
346
+ authenticated: ['/app*'],
347
+ redirectToLogin: route('/'),
348
+ // You want to redirect to the firstly UI ? change redirectToLogin to this 👇
349
+ // redirectToLogin: route('login'),
350
+ redirectAuthenticated: route('/app'),
351
+ redirect,
352
+ })
353
+ )
213
354
  `,
214
355
  ],
215
356
  './src/routes/api/[...remult]/+server.ts': [
216
- `import { api } from '${libAlias}/firstly'
357
+ `import { api } from '${serverAlias}'
217
358
 
218
359
  export const { GET, POST, PUT, DELETE } = api
219
360
  `,
220
361
  ],
221
- './src/routes/+page.svelte': [`Home 👋`, ``],
222
362
  './src/routes/+layout.server.ts': [
223
363
  `import { remult } from 'remult'
224
364
 
@@ -227,20 +367,78 @@ import type { LayoutServerLoad } from './$types'
227
367
  export const load = (async () => {
228
368
  return { user: remult.user }
229
369
  }) satisfies LayoutServerLoad
370
+ `,
371
+ ],
372
+ './src/routes/+layout.ts': [
373
+ `import { remult } from 'remult'
374
+ import type { LayoutLoad } from './$types'
375
+
376
+ export const load = (async (event) => {
377
+ // Instruct remult to use the special svelte fetch
378
+ // Like this univeral load will work in SSR & CSR
379
+ remult.useFetch(event.fetch)
380
+ // return repo(Task).find()
381
+ return { ...event.data }
382
+ }) satisfies LayoutLoad
230
383
  `,
231
384
  ],
232
385
  './src/routes/+layout.svelte': [
233
386
  `<script lang="ts">
234
- import { remult } from 'remult'
387
+ import { untrack } from 'svelte'
388
+ import { createSubscriber } from 'svelte/reactivity'
389
+
390
+ import { Remult, remult } from 'remult'
235
391
 
236
392
  import { route } from '${libAlias}/ROUTES'
237
393
  import SignIn from '${libAlias}/ui/SignIn.svelte'
238
394
  import SignOut from '${libAlias}/ui/SignOut.svelte'
239
395
 
240
- import type { LayoutData } from './$types'
241
-
242
- export let data: LayoutData
243
- $: remult.user = data.user
396
+ import type { LayoutData } from './$types'
397
+
398
+ interface Props {
399
+ data: LayoutData
400
+ children?: import('svelte').Snippet
401
+ }
402
+
403
+ let { data, children }: Props = $props()
404
+
405
+ $effect(() => {
406
+ // Trigger the effect only on data.user update
407
+ data.user
408
+ untrack(() => {
409
+ remult.user = data.user
410
+ })
411
+ })
412
+
413
+ // To be done once in the application.
414
+ function initRemultSvelteReactivity() {
415
+ // Auth reactivity (remult.user, remult.authenticated(), ...)
416
+ {
417
+ let update = () => {}
418
+ let s = createSubscriber((u) => {
419
+ update = u
420
+ })
421
+ remult.subscribeAuth({
422
+ reportObserved: () => s(),
423
+ reportChanged: () => update(),
424
+ })
425
+ }
426
+
427
+ // Entities reactivity
428
+ {
429
+ Remult.entityRefInit = (x) => {
430
+ let update = () => {}
431
+ let s = createSubscriber((u) => {
432
+ update = u
433
+ })
434
+ x.subscribe({
435
+ reportObserved: () => s(),
436
+ reportChanged: () => update(),
437
+ })
438
+ }
439
+ }
440
+ }
441
+ initRemultSvelteReactivity()
244
442
  </script>
245
443
 
246
444
  <svelte:head>
@@ -265,12 +463,21 @@ export const load = (async () => {
265
463
  <SignIn demo="Noam"></SignIn>
266
464
  <br />
267
465
  <SignIn ffLink></SignIn>
466
+ <br />
268
467
  <SignIn oauth="github"></SignIn>
269
468
  {/if}
270
469
 
271
470
  <hr />
272
471
 
273
- <slot />
472
+ <a href={route('/')}>Home</a> |
473
+ {#if remult.authenticated()}
474
+ <a href={route('/app')}>App (Protected route)</a> |
475
+ {/if}
476
+ <a href={route('/demo/task')}>Demo task</a>
477
+
478
+ <hr />
479
+
480
+ {@render children?.()}
274
481
 
275
482
  <hr />
276
483
 
@@ -283,16 +490,65 @@ export const load = (async () => {
283
490
  <a href={route('github', { owner: 'jycouet', repo: 'firstly' })} target="_blank"> ⭐️ firstly </a>
284
491
  |
285
492
  <a href={route('github', { owner: 'remult', repo: 'remult' })} target="_blank">⭐️ remult</a>
493
+ `,
494
+ ],
495
+ './src/routes/+page.ts': [
496
+ `import { remult } from 'remult'
497
+ import type { PageLoad } from './$types'
498
+
499
+ export const load = (async (event) => {
500
+ // Instruct remult to use the special svelte fetch
501
+ // Like this univeral load will work in SSR & CSR
502
+ remult.useFetch(event.fetch)
503
+ // return repo(Task).find()
504
+ }) satisfies PageLoad
505
+ `,
506
+ ],
507
+ './src/routes/+page.svelte': [
508
+ `<h1>Home</h1>
509
+
510
+ <p>
511
+ Welcome here
512
+ </p>`,
513
+ ],
514
+ './src/routes/app/+page.svelte': [
515
+ `<h1>App</h1>
516
+
517
+ <p>
518
+ Only autenticated users can see this page!
519
+ </p>
520
+
521
+ `,
522
+ ],
523
+ // Lib files
524
+ './src/lib/index.ts': [
525
+ `import { FF_Role } from 'firstly'
526
+ import { FF_Role_Auth } from 'firstly/auth/client'
527
+ import { Log } from '@kitql/helpers'
528
+
529
+ /**
530
+ * Your logs with a nice prefix, use \`log.info("Hello")\` / \`log.success("Yeah")\` / \`log.error("Ho nooo!")\` and see !
531
+ */
532
+ export const log = new Log('${pkg.name}')
533
+
534
+ /**
535
+ * Your roles, use them in your app !
536
+ */
537
+ export const Role = {
538
+ Boss: 'Boss',
539
+ ...FF_Role_Auth,
540
+ ...FF_Role,
541
+ } as const
286
542
  `,
287
543
  ],
288
544
  './src/lib/ui/SignIn.svelte': [
289
545
  `<script lang="ts">
290
546
  import { isError } from 'firstly'
291
- import { Auth } from 'firstly/auth/client'
547
+ import { AuthController } from 'firstly/auth/client'
292
548
 
293
549
  import { goto, invalidateAll } from '$app/navigation'
294
550
 
295
- import { route } from '../ROUTES'
551
+ import { route } from '${libAlias}/ROUTES'
296
552
 
297
553
  // Examples of signin modes
298
554
  export let demo = ''
@@ -301,7 +557,7 @@ export const load = (async () => {
301
557
 
302
558
  const signinDemo = async (identif: string) => {
303
559
  try {
304
- await Auth.signInDemo(identif)
560
+ await AuthController.signInDemo(identif)
305
561
  invalidateAll()
306
562
  } catch (error) {
307
563
  if (isError(error)) {
@@ -313,7 +569,7 @@ export const load = (async () => {
313
569
 
314
570
  async function signinOAuth(provider: 'github') {
315
571
  try {
316
- window.location.href = await Auth.signInOAuthGetUrl({
572
+ window.location.href = await AuthController.signInOAuthGetUrl({
317
573
  provider,
318
574
  redirect: window.location.pathname,
319
575
  })
@@ -329,7 +585,7 @@ export const load = (async () => {
329
585
  {#if demo}
330
586
  <button on:click={() => signinDemo(demo)}>Login as {demo}</button>
331
587
  {:else if ffLink}
332
- <button on:click={() => goto(route('firstly_sign_in'))}>Login with Firstly</button>
588
+ <button on:click={() => goto(route('login'))}>Login with Firstly UI</button>
333
589
  {:else if oauth}
334
590
  <button on:click={() => signinOAuth(oauth)}>Login With {oauth}</button>
335
591
  {/if}
@@ -338,13 +594,13 @@ export const load = (async () => {
338
594
  './src/lib/ui/SignOut.svelte': [
339
595
  `<script lang="ts">
340
596
  import { isError } from 'firstly'
341
- import { Auth } from 'firstly/auth/client'
597
+ import { AuthController } from 'firstly/auth/client'
342
598
 
343
599
  import { invalidateAll } from '$app/navigation'
344
600
 
345
601
  const logout = async () => {
346
602
  try {
347
- await Auth.signOut()
603
+ await AuthController.signOut()
348
604
  invalidateAll()
349
605
  } catch (error) {
350
606
  if (isError(error)) {
@@ -357,98 +613,38 @@ export const load = (async () => {
357
613
  <button on:click={logout}>Logout</button>
358
614
  `,
359
615
  ],
360
- './tsconfig.json': [
361
- `{
362
- "extends": "./.svelte-kit/tsconfig.json",
363
- "compilerOptions": {
364
- "experimentalDecorators": true,
365
- "allowJs": true,
366
- "checkJs": true,
367
- "esModuleInterop": true,
368
- "forceConsistentCasingInFileNames": true,
369
- "resolveJsonModule": true,
370
- "skipLibCheck": true,
371
- "sourceMap": true,
372
- "strict": true,
373
- "moduleResolution": "bundler"
374
- }
375
- // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
376
- //
377
- // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
378
- // from the referenced tsconfig.json - TypeScript does not merge them in
379
- }
380
- `,
381
- ],
382
- './vite.config.ts': [
383
- `import { sveltekit } from '@sveltejs/kit/vite'
384
- import { defineConfig } from 'vite'
385
-
386
- import { firstly } from 'firstly/vite'
387
-
388
- import type { KIT_ROUTES } from '${libAlias}/ROUTES'
616
+ // Task module
617
+ './src/modules/task/index.ts': [
618
+ `import { Log } from '@kitql/helpers'
389
619
 
390
- export default defineConfig({
391
- plugins: [
392
- firstly<KIT_ROUTES>({
393
- kitRoutes: {
394
- LINKS: {
395
- firstly_sign_in: 'ff/auth/sign-in',
396
- github: 'https://github.com/[owner]/[repo]',
397
- remult_admin: 'api/admin',
398
- },
399
- }
400
- }),
401
- sveltekit(),
402
- ],
403
- })
404
- `,
620
+ export const log = new Log("Custom Task Log")`,
405
621
  ],
406
- './.gitignore': [
407
- `node_modules
622
+ './src/modules/task/server/index.ts': [
623
+ `import { Module } from 'firstly/api'
408
624
 
409
- # Output
410
- /.svelte-kit
411
- /build
412
-
413
- # Env
414
- .env
415
- .env.*
416
- !.env.example
417
- !.env.test
418
-
419
- # Vite
420
- vite.config.js.timestamp-*
421
- vite.config.ts.timestamp-*
422
-
423
- # Firstly / Remult
424
- /db
425
- `,
426
- ],
427
- './src/lib/firstly/modules/task/index.ts': [
428
- `import type { Module } from 'firstly/api'
429
-
430
- import { log } from '${libAlias}/firstly'
431
-
432
- import { Task } from './Task'
433
- import { TaskController } from './TaskController'
625
+ import { Task } from '../client/Task'
626
+ import { TaskController } from '../client/TaskController'
434
627
 
435
628
  export const task: (o: { specialInfo: string }) => Module = ({ specialInfo }) => {
436
- return {
437
- name: 'task',
438
- entities: [Task],
439
- controllers: [TaskController],
440
- initApi: async () => {
441
- log.success(\`Task module is ready! 🚀 (specialInfo: \${specialInfo})\`)
442
- },
443
- }
444
- }`,
629
+ const m = new Module({
630
+ name: 'task',
631
+ entities: [Task],
632
+ controllers: [TaskController],
633
+ initApi: async () => {
634
+ m.log.success(\`Task module is ready! 🚀 (specialInfo: \${specialInfo})\`)
635
+ },
636
+ })
637
+
638
+ return m
639
+ }
640
+ `,
445
641
  ],
446
- './src/lib/firstly/modules/task/Task.ts': [
447
- `import { Entity, Field, Fields, ValueListFieldType } from 'remult'
642
+ './src/modules/task/client/Task.ts': [
643
+ `import { Allow, Entity, Field, Fields, ValueListFieldType } from 'remult'
448
644
  import { BaseEnum, LibIcon_Add, LibIcon_Delete, type BaseEnumOptions } from 'firstly'
449
645
 
450
646
  @Entity('task', {
451
- allowApiCrud: true,
647
+ allowApiCrud: Allow.authenticated,
452
648
  })
453
649
  export class Task {
454
650
  @Fields.cuid()
@@ -487,10 +683,10 @@ export class TypeOfTaskEnum extends BaseEnum {
487
683
  }
488
684
  `,
489
685
  ],
490
- './src/lib/firstly/modules/task/TaskController.ts': [
686
+ './src/modules/task/client/TaskController.ts': [
491
687
  `import { BackendMethod } from 'remult'
492
688
 
493
- import { log } from '${libAlias}/firstly'
689
+ import { log } from '${libAlias}'
494
690
 
495
691
  /**
496
692
  * await TaskController.sayHiFromTask("JYC")
@@ -501,6 +697,81 @@ export class TaskController {
501
697
  log.info(\`hello \${name} 👋\`)
502
698
  }
503
699
  }
700
+ `,
701
+ ],
702
+ './src/modules/task/ui/svelte/TaskAdd.svelte': [
703
+ `<script lang="ts">
704
+ import { EntityError, repo } from 'remult'
705
+
706
+ import { Task } from '${modulesAlias}/task/client/Task'
707
+
708
+ let task = $state(repo(Task).create())
709
+ let error = $state<EntityError<Task> | null>(null)
710
+
711
+ const add = async (e: Event) => {
712
+ e.preventDefault()
713
+ error = null
714
+ try {
715
+ await repo(Task).insert(task)
716
+ task = repo(Task).create()
717
+ } catch (e) {
718
+ if (e instanceof EntityError) {
719
+ error = e
720
+ }
721
+ }
722
+ }
723
+ </script>
724
+
725
+ <form onsubmit={add}>
726
+ <p>
727
+ {error?.modelState?.title}
728
+ </p>
729
+ <label for={repo(Task).fields.title.key}>{repo(Task).fields.title.caption}</label>
730
+ <input id={repo(Task).fields.title.key} type="text" bind:value={task.title} />
731
+ <button disabled={!repo(Task).metadata.apiInsertAllowed()}>Add</button>
732
+ </form>
733
+ `,
734
+ ],
735
+ './src/modules/task/ui/svelte/TaskList.svelte': [
736
+ `<script lang="ts">
737
+ import { repo } from 'remult'
738
+
739
+ import { Task } from '${modulesAlias}/task/client/Task'
740
+
741
+ let list: Task[] = $state([])
742
+
743
+ $effect(() => {
744
+ if (repo(Task).metadata.apiReadAllowed) {
745
+ return repo(Task)
746
+ .liveQuery()
747
+ .subscribe((info) => {
748
+ list = info.applyChanges(list)
749
+ })
750
+ }
751
+ })
752
+ </script>
753
+
754
+ {#if repo(Task).metadata.apiReadAllowed}
755
+ <ul>
756
+ {#each list as task (task.id)}
757
+ <li>{task.title}</li>
758
+ {/each}
759
+ </ul>
760
+ {:else}
761
+ <p>Login to see the task list!</p>
762
+ {/if}
763
+ `,
764
+ ],
765
+ './src/routes/demo/task/+page.svelte': [
766
+ `<script lang="ts">
767
+ import TaskAdd from '${modulesAlias}/task/ui/svelte/TaskAdd.svelte'
768
+ import TaskList from '${modulesAlias}/task/ui/svelte/TaskList.svelte'
769
+ </script>
770
+
771
+ <h1>Task Module</h1>
772
+
773
+ <TaskAdd />
774
+ <TaskList />
504
775
  `,
505
776
  ],
506
777
  };
@@ -510,7 +781,7 @@ for (const [path, content] of Object.entries(obj)) {
510
781
  }
511
782
  else {
512
783
  if (res.includes('module-demo')) {
513
- if (path.startsWith('./src/lib/firstly/modules/task')) {
784
+ if (path.startsWith('./src/modules/task')) {
514
785
  write(path, content);
515
786
  }
516
787
  }