nuxt-file-storage 0.2.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-Present Nuxt File Storage Project
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.
package/README.md ADDED
@@ -0,0 +1,160 @@
1
+ ![Nuxt Storage Banner](./playground/public/nuxt-file-storage-banner.svg)
2
+
3
+ # Nuxt File Storage
4
+
5
+ [![npm version][npm-version-src]][npm-version-href]
6
+ [![npm downloads][npm-downloads-src]][npm-downloads-href]
7
+ [![License][license-src]][license-href]
8
+ [![Nuxt][nuxt-src]][nuxt-href]
9
+
10
+
11
+ Easy solution to store files in your nuxt apps. Be able to upload files from the frontend and recieve them from the backend to then save the files in your project.
12
+
13
+ - [✨  Release Notes](/CHANGELOG.md)
14
+ - [🏀 Online playground](https://stackblitz.com/github/NyllRE/nuxt-file-storage?file=playground%2Fapp.vue)
15
+ <!-- - [📖 &nbsp;Documentation](https://example.com) -->
16
+
17
+ ## Features
18
+
19
+ <!-- Highlight some of the features your module provide here -->
20
+
21
+ - 📁 &nbsp;Get files from file input and make them ready to send to backend
22
+ - ⚗️ &nbsp;Serialize files in the backend to be able to use them appropriately
23
+ - 🖴 &nbsp;Store files in a specified location in your Nuxt backend with Nitro Engine
24
+
25
+ ## Quick Setup
26
+
27
+ 1. Add `nuxt-file-storage` dependency to your project
28
+
29
+ ```bash
30
+ # Using pnpm
31
+ pnpm add -D nuxt-file-storage
32
+
33
+ # Using yarn
34
+ yarn add --dev nuxt-file-storage
35
+
36
+ # Using npm
37
+ npm install --save-dev nuxt-file-storage
38
+ ```
39
+
40
+ 2. Add `nuxt-file-storage` to the `modules` section of `nuxt.config.ts`
41
+
42
+ ```js
43
+ export default defineNuxtConfig({
44
+ modules: ['nuxt-file-storage'],
45
+ })
46
+ ```
47
+
48
+ That's it! You can now use Nuxt Storage in your Nuxt app ✨
49
+
50
+ ## Configuration
51
+
52
+ You can currently configure a single setting of the `nuxt-file-storage` module. Here is the config interface:
53
+
54
+ ```js
55
+ export default defineNuxtConfig({
56
+ modules: ['nuxt-file-storage'],
57
+ fileStorage: {
58
+ // enter the absolute path to the location of your storage
59
+ mount: '/home/$USR/development/nuxt-file-storage/server/files',
60
+
61
+ // {OR} use environment variables (recommended)
62
+ mount: process.env.mount
63
+ // you need to set the mount in your .env file at the root of your project
64
+ },
65
+ })
66
+ ```
67
+
68
+ ## Usage
69
+
70
+ ### Handling Files in the frontend
71
+ You can use Nuxt Storage to get the files from the `<input>` tag:
72
+
73
+ ```html
74
+ <template>
75
+ <input type="file" @input="handleFileInput" />
76
+ </template>
77
+
78
+ <script setup>
79
+ // handleFileInput can handle multiple files
80
+ const { handleFileInput, files } = useFileStorage()
81
+ </script>
82
+ ```
83
+ The `files` return a ref object that contains the files
84
+
85
+ Here's an example of using files to send them to the backend:
86
+ ```html
87
+ <template>
88
+ <input type="file" @input="handleFileInput" />
89
+ <button @click="submit">submit</button>
90
+ </template>
91
+
92
+ <script setup>
93
+ const { handleFileInput, files } = useFileStorage()
94
+
95
+ const submit = async () => {
96
+ const response = await $fetch('/api/files', {
97
+ method: 'POST',
98
+ body: {
99
+ files: files.value
100
+ }
101
+ })
102
+ }
103
+ </script>
104
+ ```
105
+
106
+
107
+ ### Handling files in the backend
108
+ using Nitro Server Engine, we will make an api route that recieves the files and stores them in the folder `userFiles`
109
+ ```ts
110
+ export default defineEventHandler(async (event) => {
111
+ const { file } = await readBody<{ file: File }>(event)
112
+
113
+ await storeFileLocally(
114
+ file.content, // the stringified version of the file
115
+ file.name, // the name of the file
116
+ '/userFiles' // the folder the file will be stored in
117
+ )
118
+
119
+ // {OR}
120
+
121
+ // Parses a data URL and returns an object with the binary data and the file extension.
122
+ const { binaryString, ext } = parseDataUrl(file.content)
123
+
124
+ return 'success!'
125
+ })
126
+
127
+ interface File {
128
+ name: string
129
+ content: string
130
+ }
131
+ ```
132
+
133
+ And that's it! Now you can store any file in your nuxt project from the user ✨
134
+
135
+ ## Contribution
136
+ Run into a problem? Open a [new issue](https://github.com/NyllRE/nuxt-file-storage/issues/new). I'll try my best to include all the features requested if it is fitting to the scope of the project.
137
+
138
+ Want to add some feature? PRs are welcome!
139
+ - Clone this repository
140
+ - install the dependencies
141
+ - prepare the project
142
+ - run dev server
143
+ ```bash
144
+ git clone https://github.com/NyllRE/nuxt-file-storage && cd nuxt-file-storage
145
+ npm i
146
+ npm run dev:prepare
147
+ npm run dev
148
+ ```
149
+
150
+
151
+ <!-- Badges -->
152
+
153
+ [npm-version-src]: https://img.shields.io/npm/v/nuxt-file-storage/latest.svg?style=flat&colorA=18181B&colorB=28CF8D
154
+ [npm-version-href]: https://npmjs.com/package/nuxt-file-storage
155
+ [npm-downloads-src]: https://img.shields.io/npm/dm/nuxt-file-storage.svg?style=flat&colorA=18181B&colorB=28CF8D
156
+ [npm-downloads-href]: https://npmjs.com/package/nuxt-file-storage
157
+ [license-src]: https://img.shields.io/npm/l/nuxt-file-storage.svg?style=flat&colorA=18181B&colorB=28CF8D
158
+ [license-href]: https://npmjs.com/package/nuxt-file-storage
159
+ [nuxt-src]: https://img.shields.io/badge/Nuxt-18181B?logo=nuxt.js
160
+ [nuxt-href]: https://nuxt.com
@@ -0,0 +1,5 @@
1
+ module.exports = function(...args) {
2
+ return import('./module.mjs').then(m => m.default.call(this, ...args))
3
+ }
4
+ const _meta = module.exports.meta = require('./module.json')
5
+ module.exports.getMeta = () => Promise.resolve(_meta)
@@ -0,0 +1,8 @@
1
+ import * as _nuxt_schema from '@nuxt/schema';
2
+
3
+ interface ModuleOptions {
4
+ mount: string;
5
+ }
6
+ declare const _default: _nuxt_schema.NuxtModule<ModuleOptions>;
7
+
8
+ export { type ModuleOptions, _default as default };
@@ -0,0 +1,8 @@
1
+ import * as _nuxt_schema from '@nuxt/schema';
2
+
3
+ interface ModuleOptions {
4
+ mount: string;
5
+ }
6
+ declare const _default: _nuxt_schema.NuxtModule<ModuleOptions>;
7
+
8
+ export { type ModuleOptions, _default as default };
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "nuxt-file-storage",
3
+ "configKey": "fileStorage",
4
+ "version": "0.2.0"
5
+ }
@@ -0,0 +1,25 @@
1
+ import { defineNuxtModule, createResolver, addImportsDir } from '@nuxt/kit';
2
+ import defu from 'defu';
3
+
4
+ const module = defineNuxtModule({
5
+ meta: {
6
+ name: "nuxt-file-storage",
7
+ configKey: "fileStorage"
8
+ },
9
+ //? Default configuration options of the Nuxt module
10
+ // defaults: {
11
+ // },
12
+ setup(options, nuxt) {
13
+ nuxt.options.runtimeConfig.public.fileStorage = defu(
14
+ nuxt.options.runtimeConfig.public.fileStorage,
15
+ {
16
+ ...options
17
+ }
18
+ );
19
+ const resolver = createResolver(import.meta.url);
20
+ addImportsDir(resolver.resolve("runtime/composables"));
21
+ addImportsDir(resolver.resolve("runtime/server/utils"));
22
+ }
23
+ });
24
+
25
+ export { module as default };
@@ -0,0 +1,13 @@
1
+ export default function (): {
2
+ files: import("vue").Ref<{
3
+ content: any;
4
+ name: string;
5
+ readonly size: number;
6
+ readonly type: string;
7
+ arrayBuffer: () => Promise<ArrayBuffer>;
8
+ slice: (start?: number | undefined, end?: number | undefined, contentType?: string | undefined) => Blob;
9
+ stream: () => ReadableStream<Uint8Array>;
10
+ text: () => Promise<string>;
11
+ }[]>;
12
+ handleFileInput: (event: any) => void;
13
+ };
@@ -0,0 +1,25 @@
1
+ import { ref } from "vue";
2
+ export default function() {
3
+ const files = ref([]);
4
+ const serializeFile = (file) => {
5
+ const reader = new FileReader();
6
+ reader.onload = (e) => {
7
+ files.value.push({
8
+ ...file,
9
+ content: e.target.result
10
+ });
11
+ };
12
+ reader.readAsDataURL(file);
13
+ };
14
+ const handleFileInput = (event) => {
15
+ files.value.splice(0);
16
+ console.log("handleFileInput event: " + event);
17
+ for (const file of event.target.files) {
18
+ serializeFile(file);
19
+ }
20
+ };
21
+ return {
22
+ files,
23
+ handleFileInput
24
+ };
25
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,4 @@
1
+ import { defineNuxtPlugin } from "#app";
2
+ export default defineNuxtPlugin((nuxtApp) => {
3
+ console.log("nuxt-file-storage initialized successfully");
4
+ });
@@ -0,0 +1,16 @@
1
+ /// <reference types="node" />
2
+ /**
3
+ * @returns mime type
4
+ * @prop fileNameOrIdLength: you can pass a string or a number, if you enter a string it will be the file name, if you enter a number it will generate a unique ID
5
+ */
6
+ export declare const storeFileLocally: (dataurl: string, fileNameOrIdLength: string | number, filelocation?: string) => Promise<string>;
7
+ export declare const deleteFile: (filename: string, filelocation?: string) => Promise<void>;
8
+ /**
9
+ Parses a data URL and returns an object with the binary data and the file extension.
10
+ @param {string} file - The data URL
11
+ @returns {{ binaryString: Buffer, ext: string }} - An object with the binary data and the file extension
12
+ */
13
+ export declare const parseDataUrl: (file: string) => {
14
+ binaryString: Buffer;
15
+ ext: any;
16
+ };
@@ -0,0 +1,36 @@
1
+ import mimeTypes from "mime-types";
2
+ import { writeFile, rm, mkdir } from "fs/promises";
3
+ export const storeFileLocally = async (dataurl, fileNameOrIdLength, filelocation = "") => {
4
+ const { binaryString, ext } = parseDataUrl(dataurl);
5
+ const location = useRuntimeConfig().public.fileStorage.mount;
6
+ const filename = typeof fileNameOrIdLength == "number" ? generateRandomId(fileNameOrIdLength) : fileNameOrIdLength;
7
+ await mkdir(`${location}${filelocation}`, { recursive: true });
8
+ await writeFile(`${location}${filelocation}/${filename}.${ext}`, binaryString, {
9
+ flag: "w"
10
+ });
11
+ return `${filename}.${ext}`;
12
+ };
13
+ export const deleteFile = async (filename, filelocation = "") => {
14
+ const location = useRuntimeConfig().public.fileStorage.mount;
15
+ await rm(`${location}${filelocation}/${filename}`);
16
+ };
17
+ const generateRandomId = (length) => {
18
+ const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
19
+ let randomId = "";
20
+ for (let i = 0; i < length; i++) {
21
+ randomId += characters.charAt(Math.floor(Math.random() * characters.length));
22
+ }
23
+ return randomId;
24
+ };
25
+ export const parseDataUrl = (file) => {
26
+ const arr = file.split(",");
27
+ const mimeMatch = arr[0].match(/:(.*?);/);
28
+ if (!mimeMatch) {
29
+ throw new Error("Invalid data URL");
30
+ }
31
+ const mime = mimeMatch[1];
32
+ const base64String = arr[1];
33
+ const binaryString = Buffer.from(base64String, "base64");
34
+ const ext = mimeTypes.extension(mime);
35
+ return { binaryString, ext };
36
+ };
@@ -0,0 +1,16 @@
1
+
2
+ import type { ModuleOptions } from './module.js'
3
+
4
+
5
+ declare module '@nuxt/schema' {
6
+ interface NuxtConfig { ['fileStorage']?: Partial<ModuleOptions> }
7
+ interface NuxtOptions { ['fileStorage']?: ModuleOptions }
8
+ }
9
+
10
+ declare module 'nuxt/schema' {
11
+ interface NuxtConfig { ['fileStorage']?: Partial<ModuleOptions> }
12
+ interface NuxtOptions { ['fileStorage']?: ModuleOptions }
13
+ }
14
+
15
+
16
+ export type { ModuleOptions, default } from './module.js'
@@ -0,0 +1,16 @@
1
+
2
+ import type { ModuleOptions } from './module'
3
+
4
+
5
+ declare module '@nuxt/schema' {
6
+ interface NuxtConfig { ['fileStorage']?: Partial<ModuleOptions> }
7
+ interface NuxtOptions { ['fileStorage']?: ModuleOptions }
8
+ }
9
+
10
+ declare module 'nuxt/schema' {
11
+ interface NuxtConfig { ['fileStorage']?: Partial<ModuleOptions> }
12
+ interface NuxtOptions { ['fileStorage']?: ModuleOptions }
13
+ }
14
+
15
+
16
+ export type { ModuleOptions, default } from './module'
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "nuxt-file-storage",
3
+ "version": "0.2.0",
4
+ "description": "Easy solution to store files in your nuxt apps. Be able to upload files from the frontend and recieve them from the backend to then save the files in your project.",
5
+ "repository": "NyllRE/nuxt-file-storage",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/types.d.ts",
11
+ "import": "./dist/module.mjs",
12
+ "require": "./dist/module.cjs"
13
+ }
14
+ },
15
+ "main": "./dist/module.cjs",
16
+ "types": "./dist/types.d.ts",
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "scripts": {
21
+ "prepack": "nuxt-module-build build",
22
+ "dev": "nuxi dev playground",
23
+ "dev:build": "nuxi build playground",
24
+ "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
25
+ "release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags",
26
+ "lint": "eslint .",
27
+ "test": "vitest run",
28
+ "test:watch": "vitest watch"
29
+ },
30
+ "dependencies": {
31
+ "@nuxt/kit": "^3.9.3",
32
+ "defu": "^6.1.4"
33
+ },
34
+ "devDependencies": {
35
+ "@nuxt/devtools": "latest",
36
+ "@nuxt/eslint-config": "^0.2.0",
37
+ "@nuxt/module-builder": "^0.5.5",
38
+ "@nuxt/schema": "^3.9.3",
39
+ "@nuxt/test-utils": "^3.9.0",
40
+ "@types/mime-types": "^2.1.4",
41
+ "@types/node": "^20.11.5",
42
+ "changelogen": "^0.5.5",
43
+ "eslint": "^8.56.0",
44
+ "mime-types": "^2.1.35",
45
+ "nuxt": "^3.9.3",
46
+ "vitest": "^1.0.0"
47
+ }
48
+ }