@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
@@ -0,0 +1,337 @@
1
+ import { useSupabaseClient } from '#imports'
2
+ import type { OrderDirection } from '@lucashw68/nsdb/types/list'
3
+ import {
4
+ applySearchFilter,
5
+ joinPath,
6
+ normalizeBucketName,
7
+ normalizeDirectoryPath,
8
+ normalizeFilePath,
9
+ normalizePath,
10
+ } from '../utils/storage'
11
+
12
+ export {
13
+ applySearchFilter,
14
+ joinPath,
15
+ normalizeBucketName,
16
+ normalizeDirectoryPath,
17
+ normalizeFilePath,
18
+ normalizePath,
19
+ } from '../utils/storage'
20
+
21
+ export type StorageFileBody = File | Blob | ArrayBuffer | ArrayBufferView | FormData | string
22
+
23
+ export type StorageOrderBy =
24
+ | 'name'
25
+ | 'created_at'
26
+ | 'updated_at'
27
+ | 'last_accessed_at'
28
+
29
+ export type StorageImageResizeMode = 'cover' | 'contain' | 'fill'
30
+ export type StorageImageFormat = 'origin' | 'webp' | 'png' | 'jpeg'
31
+
32
+ export interface StorageImageTransformOptions {
33
+ width?: number
34
+ height?: number
35
+ resize?: StorageImageResizeMode
36
+ quality?: number
37
+ format?: StorageImageFormat
38
+ }
39
+
40
+ export interface StorageListOptions {
41
+ path?: string
42
+ limit?: number
43
+ offset?: number
44
+ orderBy?: StorageOrderBy
45
+ orderDirection?: OrderDirection
46
+ search?: string
47
+ }
48
+
49
+ export interface StorageWriteOptions {
50
+ cacheControl?: string
51
+ contentType?: string
52
+ metadata?: Record<string, unknown>
53
+ upsert?: boolean
54
+ }
55
+
56
+ export interface StorageDownloadOptions {
57
+ transform?: StorageImageTransformOptions
58
+ }
59
+
60
+ export interface StoragePublicUrlOptions {
61
+ download?: boolean | string
62
+ transform?: StorageImageTransformOptions
63
+ }
64
+
65
+ export interface StorageSignedUrlOptions {
66
+ download?: boolean | string
67
+ transform?: StorageImageTransformOptions
68
+ }
69
+
70
+ export interface StorageCreateBucketOptions {
71
+ public?: boolean
72
+ allowedMimeTypes?: string[]
73
+ fileSizeLimit?: number | string
74
+ }
75
+
76
+ export interface StorageApiSuccess<T> {
77
+ success: true
78
+ data: T
79
+ error: undefined
80
+ }
81
+
82
+ export interface StorageApiFailure<T> {
83
+ success: false
84
+ data: T
85
+ error: unknown
86
+ }
87
+
88
+ export type StorageApiResponse<T> = StorageApiSuccess<T> | StorageApiFailure<T>
89
+
90
+ const DEFAULT_LIST_OPTIONS: Required<Pick<StorageListOptions, 'path' | 'limit' | 'offset' | 'orderBy' | 'orderDirection'>> = {
91
+ path: '',
92
+ limit: 100,
93
+ offset: 0,
94
+ orderBy: 'name',
95
+ orderDirection: 'asc',
96
+ }
97
+
98
+ function handleStorageResponse<T>(
99
+ payload: { data: T | null; error: unknown },
100
+ context: string,
101
+ fallbackData: T
102
+ ): StorageApiResponse<T> {
103
+ const { data, error } = payload
104
+
105
+ if (error) {
106
+ console.error(`❌ [storage:${context}]`, error)
107
+ return {
108
+ success: false,
109
+ error,
110
+ data: fallbackData,
111
+ }
112
+ }
113
+
114
+ return {
115
+ success: true,
116
+ error: undefined,
117
+ data: (data ?? fallbackData) as T,
118
+ }
119
+ }
120
+
121
+ function normalizeBucketOptions(options: StorageCreateBucketOptions = {}) {
122
+ return {
123
+ public: options.public ?? false,
124
+ allowedMimeTypes: options.allowedMimeTypes,
125
+ fileSizeLimit: options.fileSizeLimit,
126
+ }
127
+ }
128
+
129
+ export const useSupabaseApiStorage = () => {
130
+ const supabaseClient = useSupabaseClient?.()
131
+
132
+ if (!supabaseClient) {
133
+ throw new Error('[nsdb] Supabase client not found. Install @nuxtjs/supabase.')
134
+ }
135
+
136
+ function bucket(bucketName: string) {
137
+ return supabaseClient.storage.from(normalizeBucketName(bucketName))
138
+ }
139
+
140
+ /**
141
+ * Liste les fichiers et dossiers d'un bucket.
142
+ * La recherche est locale car Supabase Storage ne fournit pas de recherche texte native.
143
+ */
144
+ async function list<T extends { name?: string } = any>(bucketName: string, options: StorageListOptions = {}) {
145
+ const listOptions = { ...DEFAULT_LIST_OPTIONS, ...options }
146
+ const directoryPath = normalizeDirectoryPath(listOptions.path)
147
+
148
+ const { data, error } = await bucket(bucketName).list(directoryPath, {
149
+ limit: listOptions.limit,
150
+ offset: listOptions.offset,
151
+ sortBy: {
152
+ column: listOptions.orderBy,
153
+ order: listOptions.orderDirection,
154
+ },
155
+ })
156
+
157
+ const filteredData = applySearchFilter((data ?? []) as unknown as T[], listOptions.search)
158
+ return handleStorageResponse<T[]>({ data: filteredData, error }, `LIST ${bucketName}/${directoryPath}`, [])
159
+ }
160
+
161
+ /**
162
+ * Upload un nouveau fichier. Utiliser update() pour remplacer explicitement un fichier existant.
163
+ */
164
+ async function upload<T = any>(
165
+ bucketName: string,
166
+ path: string,
167
+ fileBody: StorageFileBody,
168
+ options: StorageWriteOptions = {}
169
+ ) {
170
+ const filePath = normalizeFilePath(path)
171
+ const { data, error } = await bucket(bucketName).upload(filePath, fileBody, options as any)
172
+ return handleStorageResponse<T>({ data: data as T | null, error }, `UPLOAD ${bucketName}/${filePath}`, null as T)
173
+ }
174
+
175
+ /**
176
+ * Remplace le contenu d'un fichier existant sans changer son chemin.
177
+ */
178
+ async function update<T = any>(
179
+ bucketName: string,
180
+ path: string,
181
+ fileBody: StorageFileBody,
182
+ options: Omit<StorageWriteOptions, 'upsert'> = {}
183
+ ) {
184
+ const filePath = normalizeFilePath(path)
185
+ const { data, error } = await bucket(bucketName).update(filePath, fileBody, options as any)
186
+ return handleStorageResponse<T>({ data: data as T | null, error }, `UPDATE ${bucketName}/${filePath}`, null as T)
187
+ }
188
+
189
+ async function download(bucketName: string, path: string, options: StorageDownloadOptions = {}) {
190
+ const filePath = normalizeFilePath(path)
191
+ const { data, error } = await bucket(bucketName).download(filePath, options as any)
192
+ return handleStorageResponse<Blob>({ data, error }, `DOWNLOAD ${bucketName}/${filePath}`, null as unknown as Blob)
193
+ }
194
+
195
+ async function remove<T = any>(bucketName: string, paths: string | string[]) {
196
+ const filePaths = (Array.isArray(paths) ? paths : [paths]).map(normalizeFilePath)
197
+ const { data, error } = await bucket(bucketName).remove(filePaths)
198
+ return handleStorageResponse<T[]>({ data: data as T[] | null, error }, `REMOVE ${bucketName}`, [])
199
+ }
200
+
201
+ function getPublicUrl(bucketName: string, path: string, options: StoragePublicUrlOptions = {}) {
202
+ const filePath = normalizeFilePath(path)
203
+ const { data } = bucket(bucketName).getPublicUrl(filePath, options as any)
204
+ return data.publicUrl
205
+ }
206
+
207
+ async function createSignedUrl(
208
+ bucketName: string,
209
+ path: string,
210
+ expiresIn = 60,
211
+ options: StorageSignedUrlOptions = {}
212
+ ) {
213
+ const filePath = normalizeFilePath(path)
214
+ const { data, error } = await bucket(bucketName).createSignedUrl(filePath, expiresIn, options as any)
215
+ return handleStorageResponse<{ signedUrl: string }>(
216
+ { data, error },
217
+ `SIGNED_URL ${bucketName}/${filePath}`,
218
+ null as unknown as { signedUrl: string },
219
+ )
220
+ }
221
+
222
+ async function createSignedUrls(
223
+ bucketName: string,
224
+ paths: string[],
225
+ expiresIn = 60,
226
+ options: StorageSignedUrlOptions = {}
227
+ ) {
228
+ const filePaths = paths.map(normalizeFilePath)
229
+ const { data, error } = await bucket(bucketName).createSignedUrls(filePaths, expiresIn, options as any)
230
+ return handleStorageResponse<Array<{ path: string; signedUrl: string }>>(
231
+ { data: data as Array<{ path: string; signedUrl: string }> | null, error },
232
+ `SIGNED_URLS ${bucketName}`,
233
+ [],
234
+ )
235
+ }
236
+
237
+ async function createSignedUploadUrl(bucketName: string, path: string) {
238
+ const filePath = normalizeFilePath(path)
239
+ const { data, error } = await bucket(bucketName).createSignedUploadUrl(filePath)
240
+ return handleStorageResponse<{ signedUrl: string; path: string; token: string }>(
241
+ { data, error },
242
+ `SIGNED_UPLOAD_URL ${bucketName}/${filePath}`,
243
+ null as unknown as { signedUrl: string; path: string; token: string },
244
+ )
245
+ }
246
+
247
+ async function uploadToSignedUrl<T = any>(
248
+ bucketName: string,
249
+ path: string,
250
+ token: string,
251
+ fileBody: StorageFileBody
252
+ ) {
253
+ const filePath = normalizeFilePath(path)
254
+ const { data, error } = await bucket(bucketName).uploadToSignedUrl(filePath, token, fileBody as any)
255
+ return handleStorageResponse<T>({ data: data as T | null, error }, `UPLOAD_SIGNED_URL ${bucketName}/${filePath}`, null as T)
256
+ }
257
+
258
+ async function move<T = any>(bucketName: string, fromPath: string, toPath: string) {
259
+ const normalizedFromPath = normalizeFilePath(fromPath)
260
+ const normalizedToPath = normalizeFilePath(toPath)
261
+ const { data, error } = await bucket(bucketName).move(normalizedFromPath, normalizedToPath)
262
+ return handleStorageResponse<T>(
263
+ { data: data as T | null, error },
264
+ `MOVE ${bucketName} ${normalizedFromPath} -> ${normalizedToPath}`,
265
+ null as T,
266
+ )
267
+ }
268
+
269
+ async function copy<T = any>(bucketName: string, fromPath: string, toPath: string) {
270
+ const normalizedFromPath = normalizeFilePath(fromPath)
271
+ const normalizedToPath = normalizeFilePath(toPath)
272
+ const { data, error } = await bucket(bucketName).copy(normalizedFromPath, normalizedToPath)
273
+ return handleStorageResponse<T>(
274
+ { data: data as T | null, error },
275
+ `COPY ${bucketName} ${normalizedFromPath} -> ${normalizedToPath}`,
276
+ null as T,
277
+ )
278
+ }
279
+
280
+ async function listBuckets<T = any>() {
281
+ const { data, error } = await supabaseClient.storage.listBuckets()
282
+ return handleStorageResponse<T[]>({ data: data as T[] | null, error }, 'LIST_BUCKETS', [])
283
+ }
284
+
285
+ async function getBucket<T = any>(bucketName: string) {
286
+ const normalizedBucketName = normalizeBucketName(bucketName)
287
+ const { data, error } = await supabaseClient.storage.getBucket(normalizedBucketName)
288
+ return handleStorageResponse<T>({ data: data as T | null, error }, `GET_BUCKET ${normalizedBucketName}`, null as T)
289
+ }
290
+
291
+ async function createBucket<T = any>(bucketName: string, options: StorageCreateBucketOptions = {}) {
292
+ const normalizedBucketName = normalizeBucketName(bucketName)
293
+ const { data, error } = await supabaseClient.storage.createBucket(normalizedBucketName, normalizeBucketOptions(options))
294
+ return handleStorageResponse<T>({ data: data as T | null, error }, `CREATE_BUCKET ${normalizedBucketName}`, null as T)
295
+ }
296
+
297
+ async function updateBucket<T = any>(bucketName: string, options: StorageCreateBucketOptions) {
298
+ const normalizedBucketName = normalizeBucketName(bucketName)
299
+ const { data, error } = await supabaseClient.storage.updateBucket(normalizedBucketName, normalizeBucketOptions(options))
300
+ return handleStorageResponse<T>({ data: data as T | null, error }, `UPDATE_BUCKET ${normalizedBucketName}`, null as T)
301
+ }
302
+
303
+ async function deleteBucket<T = any>(bucketName: string) {
304
+ const normalizedBucketName = normalizeBucketName(bucketName)
305
+ const { data, error } = await supabaseClient.storage.deleteBucket(normalizedBucketName)
306
+ return handleStorageResponse<T>({ data: data as T | null, error }, `DELETE_BUCKET ${normalizedBucketName}`, null as T)
307
+ }
308
+
309
+ async function emptyBucket<T = any>(bucketName: string) {
310
+ const normalizedBucketName = normalizeBucketName(bucketName)
311
+ const { data, error } = await supabaseClient.storage.emptyBucket(normalizedBucketName)
312
+ return handleStorageResponse<T>({ data: data as T | null, error }, `EMPTY_BUCKET ${normalizedBucketName}`, null as T)
313
+ }
314
+
315
+ return {
316
+ list,
317
+ upload,
318
+ update,
319
+ download,
320
+ remove,
321
+ getPublicUrl,
322
+ createSignedUrl,
323
+ createSignedUrls,
324
+ createSignedUploadUrl,
325
+ uploadToSignedUrl,
326
+ move,
327
+ copy,
328
+ listBuckets,
329
+ getBucket,
330
+ createBucket,
331
+ updateBucket,
332
+ deleteBucket,
333
+ emptyBucket,
334
+ joinPath,
335
+ normalizePath,
336
+ }
337
+ }