@lucashw68/nsdb 1.0.0-rc.2

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 (49) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/GET_STARTED.md +709 -0
  3. package/LICENSE +21 -0
  4. package/README.md +159 -0
  5. package/cli/index.js +83 -0
  6. package/helpers/args.js +22 -0
  7. package/helpers/config.js +142 -0
  8. package/helpers/generated.js +48 -0
  9. package/helpers/io.js +39 -0
  10. package/helpers/metadata.js +19 -0
  11. package/helpers/names.js +16 -0
  12. package/helpers/relations.js +101 -0
  13. package/helpers/shell.js +15 -0
  14. package/helpers/tables.js +79 -0
  15. package/helpers/ts.js +37 -0
  16. package/module.ts +151 -0
  17. package/nsdb.config.example.mjs +39 -0
  18. package/nsdb.config.example.ts +42 -0
  19. package/package.json +114 -0
  20. package/runtime/components/Form/NsdbRelationSelect.vue +258 -0
  21. package/runtime/components/NsdbForm.vue +865 -0
  22. package/runtime/components/NsdbList.vue +961 -0
  23. package/runtime/composables/useNsdbProfile.ts +119 -0
  24. package/runtime/composables/useNsdbSchemas.ts +176 -0
  25. package/runtime/composables/useSupabaseApi.ts +177 -0
  26. package/runtime/composables/useSupabaseApiStorage.ts +337 -0
  27. package/runtime/composables/useSupabaseModels.ts +412 -0
  28. package/runtime/query.ts +126 -0
  29. package/runtime/stores/createDbStore.ts +439 -0
  30. package/runtime/stores/createSingletonDbStore.ts +67 -0
  31. package/runtime/utils/dataFreshness.ts +47 -0
  32. package/runtime/utils/storage.ts +41 -0
  33. package/scripts/clear.js +64 -0
  34. package/scripts/generate-composables.js +100 -0
  35. package/scripts/generate-enums.js +106 -0
  36. package/scripts/generate-metadata.js +165 -0
  37. package/scripts/generate-models.js +164 -0
  38. package/scripts/generate-schemas.js +443 -0
  39. package/scripts/generate-stores.js +90 -0
  40. package/scripts/generate-types.js +196 -0
  41. package/scripts/init.js +225 -0
  42. package/templates/model.template.ts +48 -0
  43. package/templates/schema.template.ts +13 -0
  44. package/templates/useNsdbModel.template.ts +9 -0
  45. package/types/config.ts +50 -0
  46. package/types/entities.ts +66 -0
  47. package/types/index.ts +14 -0
  48. package/types/list.ts +78 -0
  49. package/types/model.ts +57 -0
package/GET_STARTED.md ADDED
@@ -0,0 +1,709 @@
1
+ # Get Started — Installer NSDB dans un projet Nuxt 4
2
+
3
+ Ce guide décrit l'installation complète de NSDB dans une app Nuxt 4 existante.
4
+
5
+ > **Statut de publication :** `1.0.0-rc.2` est la release candidate actuelle et n'est pas encore disponible sur npm. Ces commandes d'installation s'appliqueront après publication.
6
+
7
+ NSDB est un module Nuxt qui facilite l'utilisation de Supabase dans Nuxt avec :
8
+
9
+ - génération des types Supabase
10
+ - génération de schemas NSDB par table
11
+ - génération de modèles/composables typés
12
+ - composants `NsdbList` et `NsdbForm`
13
+ - stores Pinia optionnels
14
+ - helpers pour Supabase Database et Storage
15
+
16
+ ---
17
+
18
+ ## 1. Prérequis
19
+
20
+ Vous devez avoir :
21
+
22
+ - une app Nuxt 4
23
+ - un projet Supabase
24
+ - des tables Supabase existantes
25
+ - les RLS Supabase prévues pour sécuriser les accès
26
+ - Node.js et un package manager (`npm`, `pnpm` ou `yarn`)
27
+
28
+ Si vous utilisez Supabase Auth, le module recommandé côté Nuxt est `@nuxtjs/supabase`.
29
+
30
+ ---
31
+
32
+ ## 2. Installer les dépendances
33
+
34
+ Avec npm :
35
+
36
+ ```bash
37
+ npm install @lucashw68/nsdb @nuxtjs/supabase @pinia/nuxt pinia
38
+ npm install -D supabase
39
+ ```
40
+
41
+ Avec pnpm :
42
+
43
+ ```bash
44
+ pnpm add @lucashw68/nsdb @nuxtjs/supabase @pinia/nuxt pinia
45
+ pnpm add -D supabase
46
+ ```
47
+
48
+ Avec yarn :
49
+
50
+ ```bash
51
+ yarn add @lucashw68/nsdb @nuxtjs/supabase @pinia/nuxt pinia
52
+ yarn add -D supabase
53
+ ```
54
+
55
+ Pour activer la persistance locale des stores :
56
+
57
+ ```bash
58
+ npm install pinia-plugin-persistedstate
59
+ ```
60
+
61
+ ---
62
+
63
+ ## 3. Configurer Nuxt
64
+
65
+ Ajoutez NSDB, Pinia et Supabase dans `nuxt.config.ts`.
66
+
67
+ ```ts
68
+ export default defineNuxtConfig({
69
+ modules: [
70
+ '@lucashw68/nsdb',
71
+ '@pinia/nuxt',
72
+ '@nuxtjs/supabase',
73
+ 'pinia-plugin-persistedstate/nuxt',
74
+ ],
75
+
76
+ nsdb: {
77
+ withComponents: true,
78
+ componentsPrefix: 'Nsdb',
79
+ withStores: true,
80
+ autoImportModels: true,
81
+ },
82
+
83
+ supabase: {
84
+ redirectOptions: {
85
+ login: '/',
86
+ callback: '/confirm',
87
+ exclude: ['/', '/public'],
88
+ },
89
+ },
90
+ })
91
+ ```
92
+
93
+ Si vous n'utilisez pas les stores persistés, retirez simplement :
94
+
95
+ ```ts
96
+ 'pinia-plugin-persistedstate/nuxt'
97
+ ```
98
+
99
+ ---
100
+
101
+ ## 4. Ajouter les variables d'environnement
102
+
103
+ Créez ou complétez `.env`.
104
+
105
+ ```bash
106
+ SUPABASE_URL=https://your-project.supabase.co
107
+ SUPABASE_KEY=your-anon-key
108
+ SUPABASE_PROJECT_ID=your-project-id
109
+ # Self-hosted uniquement, pour générer les types sans project id :
110
+ SUPABASE_DB_URL=postgresql://postgres:password@localhost:5432/postgres
111
+ # Self-hosted avec génération sur VPS :
112
+ SUPABASE_REMOTE_SSH_HOST=vps
113
+ SUPABASE_REMOTE_PROJECT_PATH=/opt/supabase-projects/example
114
+ SUPABASE_REMOTE_DB_URL=postgresql://postgres:$POSTGRES_PASSWORD@db:5432/postgres
115
+ ```
116
+
117
+ `SUPABASE_URL` et `SUPABASE_KEY` sont utilisés par `@nuxtjs/supabase`.
118
+
119
+ `SUPABASE_PROJECT_ID` est utilisé par NSDB pour générer les types Supabase avec le CLI Supabase.
120
+
121
+ Si votre projet Supabase est déjà lié localement avec le Supabase CLI, vous pouvez utiliser `--linked` et ne pas renseigner `SUPABASE_PROJECT_ID`.
122
+
123
+ Si vous utilisez Supabase en self-hosted, vous pouvez utiliser `SUPABASE_DB_URL` à la place de `SUPABASE_PROJECT_ID`.
124
+
125
+ Si Postgres n'est pas exposé publiquement, utilisez `SUPABASE_REMOTE_*` pour générer les types sur le VPS via SSH puis les copier localement avec `scp`.
126
+
127
+ ---
128
+
129
+ ## 5. Initialiser NSDB
130
+
131
+ Depuis la racine de votre projet Nuxt :
132
+
133
+ ```bash
134
+ npx @lucashw68/nsdb init
135
+ ```
136
+
137
+ Avec yarn :
138
+
139
+ ```bash
140
+ yarn nsdb init
141
+ ```
142
+
143
+ Options disponibles :
144
+
145
+ ```bash
146
+ nsdb init --linked
147
+ nsdb init --schema private
148
+ nsdb init --project-id your-project-id
149
+ nsdb init --self-hosted
150
+ nsdb init --db-url postgresql://postgres:password@localhost:5432/postgres
151
+ nsdb init --remote-types
152
+ nsdb init --remote-ssh-host vps --remote-project-path /opt/supabase-projects/example
153
+ nsdb init --force
154
+ ```
155
+
156
+ Exemples :
157
+
158
+ ```bash
159
+ npx @lucashw68/nsdb init --schema public --project-id abcdefghijkl
160
+ ```
161
+
162
+ ```bash
163
+ npx @lucashw68/nsdb init --linked --schema public
164
+ ```
165
+
166
+ Instance Supabase self-hosted :
167
+
168
+ ```bash
169
+ npx @lucashw68/nsdb init --self-hosted --schema public
170
+ ```
171
+
172
+ ou avec une URL Postgres explicite :
173
+
174
+ ```bash
175
+ npx @lucashw68/nsdb init --db-url postgresql://postgres:password@localhost:5432/postgres
176
+ ```
177
+
178
+ Instance Supabase self-hosted sur VPS sans Postgres exposé :
179
+
180
+ ```bash
181
+ npx @lucashw68/nsdb init --remote-types
182
+ ```
183
+
184
+ ou avec les valeurs explicites :
185
+
186
+ ```bash
187
+ npx @lucashw68/nsdb init \
188
+ --remote-ssh-host vps \
189
+ --remote-project-path /opt/supabase-projects/example \
190
+ --remote-db-url 'postgresql://postgres:$POSTGRES_PASSWORD@db:5432/postgres'
191
+ ```
192
+
193
+ `nsdb init` crée :
194
+
195
+ - `nsdb.config.ts`
196
+ - `.env.example` si absent
197
+ - les dossiers `types`, `nsdb/schemas`, `nsdb/models`, `nsdb/composables`, `stores`
198
+ - les scripts `nsdb:*` dans `package.json`
199
+
200
+ Les fichiers existants ne sont pas écrasés sauf si vous utilisez `--force`.
201
+
202
+ ---
203
+
204
+ ## 6. Vérifier `nsdb.config.ts`
205
+
206
+ Exemple standard :
207
+
208
+ ```ts
209
+ import type { NsdbConfig } from '@lucashw68/nsdb/types/config'
210
+
211
+ export default {
212
+ supabase: {
213
+ schema: 'public',
214
+ projectId: process.env.SUPABASE_PROJECT_ID,
215
+ linked: false,
216
+ },
217
+ paths: {
218
+ types: 'types/database.types.ts',
219
+ metadata: 'nsdb/database.metadata.json',
220
+ enums: 'nsdb/enums.ts',
221
+ schemas: 'nsdb/schemas',
222
+ models: 'nsdb/models',
223
+ composables: 'nsdb/composables',
224
+ stores: 'stores',
225
+ },
226
+ imports: {
227
+ databaseTypes: '~~/types/database.types',
228
+ },
229
+ tables: {
230
+ include: ['playlists', 'tracks'],
231
+ columns: {
232
+ playlists: {
233
+ internal_note: { serverOnly: true },
234
+ created_at: { editable: false },
235
+ cover_url: { hidden: true },
236
+ },
237
+ },
238
+ },
239
+ } satisfies NsdbConfig
240
+ ```
241
+
242
+ Avec `supabase.dbUrl` ou `SUPABASE_DB_URL`, `generate:all` interroge aussi `pg_catalog` afin de détecter exactement clés primaires, contraintes, valeurs par défaut, nullabilité, identités et colonnes générées. Sans accès PostgreSQL direct, cette étape est ignorée avec un avertissement et la génération utilise le fallback TypeScript moins précis.
243
+
244
+ `serverOnly` retire la colonne des artefacts client NSDB, mais ne remplace jamais RLS. En cas de collision entre un composable applicatif et un modèle généré (par exemple deux `usePlaylists`), Nuxt échoue explicitement. Configurez `autoImportModels: false` puis importez le modèle généré explicitement.
245
+
246
+ Si le projet Supabase est lié localement :
247
+
248
+ ```ts
249
+ import type { NsdbConfig } from '@lucashw68/nsdb/types/config'
250
+
251
+ export default {
252
+ supabase: {
253
+ schema: 'public',
254
+ linked: true,
255
+ },
256
+ } satisfies NsdbConfig
257
+ ```
258
+
259
+ Pour une instance Supabase self-hosted sans project id :
260
+
261
+ ```ts
262
+ import type { NsdbConfig } from '@lucashw68/nsdb/types/config'
263
+
264
+ export default {
265
+ supabase: {
266
+ schema: 'public',
267
+ dbUrl: process.env.SUPABASE_DB_URL,
268
+ linked: false,
269
+ },
270
+ } satisfies NsdbConfig
271
+ ```
272
+
273
+ Pour générer les types directement sur le VPS :
274
+
275
+ ```ts
276
+ import type { NsdbConfig } from '@lucashw68/nsdb/types/config'
277
+
278
+ export default {
279
+ supabase: {
280
+ schema: 'public',
281
+ remoteTypes: {
282
+ sshHost: process.env.SUPABASE_REMOTE_SSH_HOST,
283
+ projectPath: process.env.SUPABASE_REMOTE_PROJECT_PATH,
284
+ dbUrl: process.env.SUPABASE_REMOTE_DB_URL,
285
+ remoteOutput: '/tmp/database.types.ts',
286
+ beforeCommand: process.env.SUPABASE_REMOTE_BEFORE_COMMAND,
287
+ supabaseCommand: process.env.SUPABASE_REMOTE_SUPABASE_COMMAND,
288
+ },
289
+ linked: false,
290
+ },
291
+ } satisfies NsdbConfig
292
+ ```
293
+
294
+ Ce mode exécute la génération sur le VPS, puis copie le fichier généré en local :
295
+
296
+ ```bash
297
+ ssh vps 'cd /opt/supabase-projects/example && npx supabase gen types typescript --db-url "postgresql://postgres:$POSTGRES_PASSWORD@db:5432/postgres" > /tmp/database.types.ts'
298
+ scp vps:/tmp/database.types.ts ./types/database.types.ts
299
+ ```
300
+
301
+ Si le serveur retourne `command not found: npx`, le shell SSH non interactif ne charge probablement pas Node ou `nvm`.
302
+
303
+ Ajoutez dans `.env` :
304
+
305
+ ```bash
306
+ SUPABASE_REMOTE_BEFORE_COMMAND='source ~/.nvm/nvm.sh'
307
+ SUPABASE_REMOTE_SUPABASE_COMMAND='npx supabase'
308
+ ```
309
+
310
+ Si Supabase CLI est installé dans le projet distant :
311
+
312
+ ```bash
313
+ SUPABASE_REMOTE_SUPABASE_COMMAND='./node_modules/.bin/supabase'
314
+ ```
315
+
316
+ ---
317
+
318
+ ## 7. Générer les fichiers NSDB
319
+
320
+ Lancez :
321
+
322
+ ```bash
323
+ npm run nsdb:all
324
+ ```
325
+
326
+ Avec yarn :
327
+
328
+ ```bash
329
+ yarn nsdb:all
330
+ ```
331
+
332
+ Cette commande génère :
333
+
334
+ | Étape | Sortie | Rôle |
335
+ |-------|--------|------|
336
+ | Types | `types/database.types.ts` | Types Supabase |
337
+ | Enums | `nsdb/enums.ts` | Enums du schema |
338
+ | Schemas | `nsdb/schemas/*` | Schemas UI par table |
339
+ | Models | `nsdb/models/*` | Modèles typés par table |
340
+ | Stores | `stores/*` | Stores Pinia optionnels |
341
+ | Composable | `nsdb/composables/useNsdbModels.ts` | Accès générique aux modèles |
342
+
343
+ Vous pouvez aussi lancer une étape précise :
344
+
345
+ ```bash
346
+ npm run nsdb:types
347
+ npm run nsdb:schemas
348
+ npm run nsdb:models
349
+ npm run nsdb:stores
350
+ ```
351
+
352
+ Pour regénérer les stores en écrasant les stores existants :
353
+
354
+ ```bash
355
+ npx @lucashw68/nsdb generate:stores --force
356
+ ```
357
+
358
+ ---
359
+
360
+ ## 8. Configurer les RLS Supabase
361
+
362
+ NSDB ne remplace pas les RLS. Les droits doivent rester côté Supabase.
363
+
364
+ Exemple avec :
365
+
366
+ - `profiles.id = auth.users.id`
367
+ - `playlists.profile_id -> profiles.id`
368
+
369
+ ```sql
370
+ alter table profiles enable row level security;
371
+ alter table playlists enable row level security;
372
+
373
+ create policy "Users can read own profile"
374
+ on profiles
375
+ for select
376
+ to authenticated
377
+ using (id = auth.uid());
378
+
379
+ create policy "Users can update own profile"
380
+ on profiles
381
+ for update
382
+ to authenticated
383
+ using (id = auth.uid())
384
+ with check (id = auth.uid());
385
+
386
+ create policy "Users can read own playlists"
387
+ on playlists
388
+ for select
389
+ to authenticated
390
+ using (profile_id = auth.uid());
391
+
392
+ create policy "Users can create own playlists"
393
+ on playlists
394
+ for insert
395
+ to authenticated
396
+ with check (profile_id = auth.uid());
397
+
398
+ create policy "Users can update own playlists"
399
+ on playlists
400
+ for update
401
+ to authenticated
402
+ using (profile_id = auth.uid())
403
+ with check (profile_id = auth.uid());
404
+
405
+ create policy "Users can delete own playlists"
406
+ on playlists
407
+ for delete
408
+ to authenticated
409
+ using (profile_id = auth.uid());
410
+ ```
411
+
412
+ Si votre schema utilise `profiles.user_id` au lieu de `profiles.id = auth.uid()`, adaptez les conditions avec une sous-requête vers `profiles`.
413
+
414
+ ---
415
+
416
+ ## 9. Ajouter un trigger `profile_id`
417
+
418
+ Si vos tables métier ont une colonne `profile_id`, vous pouvez éviter de l'envoyer depuis le client.
419
+
420
+ Fonction générique :
421
+
422
+ ```sql
423
+ create or replace function public.set_profile_id()
424
+ returns trigger as $$
425
+ begin
426
+ if new.profile_id is null then
427
+ new.profile_id := (select auth.uid());
428
+ end if;
429
+
430
+ return new;
431
+ end;
432
+ $$
433
+ language plpgsql
434
+ security definer
435
+ set search_path = '';
436
+ ```
437
+
438
+ Trigger pour `playlists` :
439
+
440
+ ```sql
441
+ drop trigger if exists set_profile_id on public.playlists;
442
+
443
+ create trigger set_profile_id
444
+ before insert on public.playlists
445
+ for each row
446
+ execute function public.set_profile_id();
447
+ ```
448
+
449
+ Vous pouvez réutiliser la même fonction sur chaque table qui possède `profile_id`.
450
+
451
+ ---
452
+
453
+ ## 10. Utiliser un modèle généré
454
+
455
+ Après génération, NSDB expose des modèles par table.
456
+
457
+ Exemple avec `playlists` :
458
+
459
+ ```vue
460
+ <script setup lang="ts">
461
+ const playlists = usePlaylists()
462
+
463
+ await playlists.fetch({
464
+ orderBy: 'created_at',
465
+ orderDirection: 'desc',
466
+ limit: 20,
467
+ })
468
+
469
+ const created = await playlists.create({
470
+ title: 'Ma playlist',
471
+ })
472
+
473
+ await playlists.update(created, {
474
+ title: 'Titre modifie',
475
+ })
476
+
477
+ await playlists.remove(created)
478
+ </script>
479
+ ```
480
+
481
+ API principale d'un modèle :
482
+
483
+ ```ts
484
+ items
485
+ totalCount
486
+ loading
487
+ error
488
+ stale
489
+ createDraft
490
+ fetch
491
+ refresh
492
+ invalidate
493
+ getById
494
+ create
495
+ update
496
+ remove
497
+ subscribe
498
+ unsubscribe
499
+ ```
500
+
501
+ `fetch()` réutilise un résultat encore frais uniquement en mode store. `refresh()`
502
+ interroge toujours Supabase. `invalidate()` conserve les lignes sûres à l'écran,
503
+ mais les marque périmées. Les anciens `sync()`, `find()`, `new()` et
504
+ `fetch({ force: true })` ont été retirés dans la release candidate. Utilisez
505
+ respectivement `subscribe()`, `fetch({ where })`, `createDraft()` et `refresh()`.
506
+
507
+ ---
508
+
509
+ ## 11. Utiliser `NsdbList`
510
+
511
+ ```vue
512
+ <template>
513
+ <NsdbList
514
+ model="playlists"
515
+ :columns="columns"
516
+ :page-size="10"
517
+ searchable
518
+ :search-columns="['title', 'provider']"
519
+ :query="{
520
+ orderBy: 'created_at',
521
+ orderDirection: 'desc'
522
+ }"
523
+ />
524
+ </template>
525
+
526
+ <script setup lang="ts">
527
+ const columns = [
528
+ { key: 'title', label: 'Titre' },
529
+ { key: 'provider', label: 'Provider' },
530
+ { key: 'created_at', label: 'Créée le' },
531
+ ]
532
+ </script>
533
+ ```
534
+
535
+ Avec relation Supabase :
536
+
537
+ ```vue
538
+ <NsdbList
539
+ model="playlists"
540
+ :columns="[
541
+ { key: 'title', label: 'Titre' },
542
+ { key: 'profile.username', label: 'Auteur' }
543
+ ]"
544
+ :query="{
545
+ select: '*, profile:profiles!playlists_profile_id_fkey(*)'
546
+ }"
547
+ />
548
+ ```
549
+
550
+ ---
551
+
552
+ ## 12. Utiliser `NsdbForm`
553
+
554
+ ```vue
555
+ <template>
556
+ <NsdbForm
557
+ model="playlists"
558
+ :hide-fields="['id', 'profile_id', 'created_at', 'updated_at']"
559
+ @created="onCreated"
560
+ @error="onError"
561
+ />
562
+ </template>
563
+
564
+ <script setup lang="ts">
565
+ function onCreated(row: unknown) {
566
+ console.log('created', row)
567
+ }
568
+
569
+ function onError(error: unknown) {
570
+ console.error(error)
571
+ }
572
+ </script>
573
+ ```
574
+
575
+ Mode édition :
576
+
577
+ ```vue
578
+ <NsdbForm
579
+ model="playlists"
580
+ :id="playlistId"
581
+ :hide-fields="['id', 'profile_id', 'created_at', 'updated_at']"
582
+ />
583
+ ```
584
+
585
+ ---
586
+
587
+ ## 13. Utiliser les stores optionnels
588
+
589
+ Les stores sont utiles si vous voulez :
590
+
591
+ - conserver des données localement
592
+ - limiter certains appels Supabase
593
+ - centraliser l'état d'une table
594
+ - utiliser `pinia-plugin-persistedstate`
595
+
596
+ ```vue
597
+ <script setup lang="ts">
598
+ const playlistsStore = usePlaylistsStore()
599
+
600
+ await playlistsStore.fetchFromSupabase({
601
+ limit: 20,
602
+ staleTimeMs: 60_000,
603
+ })
604
+
605
+ const playlist = playlistsStore.getById('playlist-id')
606
+
607
+ await playlistsStore.create({
608
+ title: 'Depuis le store',
609
+ })
610
+ </script>
611
+ ```
612
+
613
+ Les stores générés sont vidés automatiquement quand l'utilisateur Supabase change.
614
+ Deux appels `usePlaylists({ store: true })` partagent la même collection : une
615
+ création, modification ou suppression confirmée par Supabase est donc visible par
616
+ tous les consommateurs sans `refresh()` supplémentaire.
617
+
618
+ ```ts
619
+ const playlists = usePlaylists({ store: true })
620
+
621
+ await playlists.fetch() // cache exact tant que le TTL est valide
622
+ await playlists.refresh() // réseau immédiatement
623
+ playlists.invalidate() // conserve items, stale devient true
624
+
625
+ playlists.subscribe() // Realtime opt-in, côté client uniquement
626
+ await playlists.unsubscribe()
627
+ ```
628
+
629
+ Les vues filtrées, décalées ou contenant des relations sont invalidées après un
630
+ événement ambigu au lieu d'être réévaluées approximativement dans le navigateur.
631
+ Pour une dépendance métier entre deux tables, invalidez-la explicitement :
632
+
633
+ ```ts
634
+ await playlists.create({ title: 'Nouvelle playlist' })
635
+ tracks.invalidate()
636
+ ```
637
+
638
+ Pour un store public non lié à l'utilisateur :
639
+
640
+ ```ts
641
+ export const usePublicCategoriesStore = createDbStore<Category>('categories', {
642
+ key: 'id',
643
+ orderBy: 'name',
644
+ defaultSort: 'asc',
645
+ scopeToUser: false,
646
+ })
647
+ ```
648
+
649
+ ---
650
+
651
+ ## 14. Utiliser Supabase Storage
652
+
653
+ ```vue
654
+ <script setup lang="ts">
655
+ const storage = useSupabaseApiStorage()
656
+
657
+ await storage.upload('avatars', 'users/me.png', file, {
658
+ upsert: true,
659
+ contentType: file.type,
660
+ })
661
+
662
+ const publicUrl = storage.getPublicUrl('avatars', 'users/me.png')
663
+ const signedUrl = await storage.createSignedUrl('avatars', 'users/me.png', 300)
664
+
665
+ await storage.remove('avatars', 'users/me.png')
666
+ </script>
667
+ ```
668
+
669
+ ---
670
+
671
+ ## 15. Vérifier l'installation
672
+
673
+ Lancez le serveur Nuxt :
674
+
675
+ ```bash
676
+ npm run dev
677
+ ```
678
+
679
+ Puis vérifiez :
680
+
681
+ - les fichiers `types/database.types.ts` et `nsdb/models/*` existent
682
+ - les composables générés sont auto-importés
683
+ - `NsdbList` affiche bien des données
684
+ - les créations passent sans envoyer `profile_id` si le trigger est actif
685
+ - les RLS bloquent les accès non autorisés
686
+
687
+ Pour vérifier le typage :
688
+
689
+ ```bash
690
+ npx nuxi typecheck
691
+ ```
692
+
693
+ ---
694
+
695
+ ## 16. Checklist rapide
696
+
697
+ - [ ] Installer `@lucashw68/nsdb`
698
+ - [ ] Installer `@nuxtjs/supabase`
699
+ - [ ] Installer Pinia
700
+ - [ ] Ajouter les modules dans `nuxt.config.ts`
701
+ - [ ] Ajouter `.env`
702
+ - [ ] Lancer `npx @lucashw68/nsdb init`
703
+ - [ ] Vérifier `nsdb.config.ts`
704
+ - [ ] Lancer `npm run nsdb:all`
705
+ - [ ] Ajouter RLS Supabase
706
+ - [ ] Ajouter triggers `profile_id` si nécessaire
707
+ - [ ] Tester `NsdbList`
708
+ - [ ] Tester `NsdbForm`
709
+ - [ ] Tester création/update/delete avec un utilisateur connecté
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lucas Heitzmann
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.