nuxt-users
Version:
A comprehensive user management module for Nuxt 3 and Nuxt 4 applications with authentication, authorization, database support, and CLI tools
230 lines (227 loc) • 8.54 kB
JavaScript
import { defineNuxtModule, createResolver, addPlugin, addImportsDir, addRouteMiddleware, addServerHandler, addComponent } from '@nuxt/kit';
import { defu } from 'defu';
export * from '../dist/runtime/server/utils/index.js';
const defaultOptions = {
connector: {
name: "sqlite",
options: {
path: "./data/users.sqlite3"
}
},
apiBasePath: "/api/nuxt-users",
tables: {
migrations: "migrations",
users: "users",
personalAccessTokens: "personal_access_tokens",
passwordResetTokens: "password_reset_tokens"
},
mailer: {
// Added default mailer (example using ethereal.email)
host: "smtp.ethereal.email",
port: 587,
secure: false,
auth: {
user: "user@ethereal.email",
// Replace with actual Ethereal user
pass: "password"
// Replace with actual Ethereal password
},
defaults: {
from: '"Nuxt Users Module" <noreply@example.com>'
}
},
passwordResetBaseUrl: "http://localhost:3000",
auth: {
whitelist: [],
tokenExpiration: 24 * 60,
// 24 hours
permissions: {}
// Empty by default - whitelist approach
},
passwordValidation: {
minLength: 8,
requireUppercase: true,
requireLowercase: true,
requireNumbers: true,
requireSpecialChars: true,
preventCommonPasswords: true
}
};
const module = defineNuxtModule({
meta: {
name: "nuxt-users",
configKey: "nuxtUsers"
},
// Default configuration options of the Nuxt module
defaults: defaultOptions,
async setup(options, nuxt) {
const resolver = createResolver(import.meta.url);
const runtimeConfigOptions = defu(options, nuxt.options.runtimeConfig.nuxtUsers || {}, defaultOptions);
nuxt.options.runtimeConfig.nuxtUsers = {
...runtimeConfigOptions,
apiBasePath: options.apiBasePath || defaultOptions.apiBasePath,
tables: {
migrations: options.tables?.migrations || defaultOptions.tables.migrations,
users: options.tables?.users || defaultOptions.tables.users,
personalAccessTokens: options.tables?.personalAccessTokens || defaultOptions.tables.personalAccessTokens,
passwordResetTokens: options.tables?.passwordResetTokens || defaultOptions.tables.passwordResetTokens
},
auth: {
whitelist: [...defaultOptions.auth?.whitelist || [], ...options.auth?.whitelist || []],
tokenExpiration: options.auth?.tokenExpiration || defaultOptions.auth.tokenExpiration,
permissions: options.auth?.permissions || defaultOptions.auth.permissions
}
};
nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
nuxt.options.runtimeConfig.public.nuxtUsers = {
passwordValidation: {
minLength: options.passwordValidation?.minLength || defaultOptions.passwordValidation.minLength,
requireUppercase: options.passwordValidation?.requireUppercase ?? defaultOptions.passwordValidation.requireUppercase,
requireLowercase: options.passwordValidation?.requireLowercase ?? defaultOptions.passwordValidation.requireLowercase,
requireNumbers: options.passwordValidation?.requireNumbers ?? defaultOptions.passwordValidation.requireNumbers,
requireSpecialChars: options.passwordValidation?.requireSpecialChars ?? defaultOptions.passwordValidation.requireSpecialChars,
preventCommonPasswords: options.passwordValidation?.preventCommonPasswords ?? defaultOptions.passwordValidation.preventCommonPasswords
},
auth: {
whitelist: [...defaultOptions.auth?.whitelist || [], ...options.auth?.whitelist || []],
permissions: options.auth?.permissions || defaultOptions.auth.permissions
},
apiBasePath: options.apiBasePath || defaultOptions.apiBasePath
};
addPlugin({
src: resolver.resolve("./runtime/plugin"),
mode: "server"
});
addImportsDir(resolver.resolve("./runtime/composables"));
addRouteMiddleware({
name: "authorization.client",
path: resolver.resolve("./runtime/middleware/authorization.client"),
global: true
});
const base = nuxt.options.runtimeConfig.nuxtUsers.apiBasePath || defaultOptions.apiBasePath;
addServerHandler({
route: `${base}/session`,
method: "post",
handler: resolver.resolve("./runtime/server/api/nuxt-users/session/index.post")
});
addServerHandler({
route: `${base}/session`,
method: "delete",
handler: resolver.resolve("./runtime/server/api/nuxt-users/session/index.delete")
});
addServerHandler({
route: `${base}/me`,
method: "get",
handler: resolver.resolve("./runtime/server/api/nuxt-users/me.get")
});
addServerHandler({
route: `${base}/me`,
method: "patch",
handler: resolver.resolve("./runtime/server/api/nuxt-users/me.patch")
});
addServerHandler({
route: `${base}/password`,
method: "patch",
handler: resolver.resolve("./runtime/server/api/nuxt-users/password/index.patch")
});
addServerHandler({
route: `${base}/password/forgot`,
method: "post",
handler: resolver.resolve("./runtime/server/api/nuxt-users/password/forgot.post")
});
addServerHandler({
route: `${base}/password/reset`,
method: "post",
handler: resolver.resolve("./runtime/server/api/nuxt-users/password/reset.post")
});
addServerHandler({
route: `${base}`,
method: "get",
handler: resolver.resolve("./runtime/server/api/nuxt-users/index.get")
});
addServerHandler({
route: `${base}`,
method: "post",
handler: resolver.resolve("./runtime/server/api/nuxt-users/index.post")
});
addServerHandler({
route: `${base}/:id`,
method: "get",
handler: resolver.resolve("./runtime/server/api/nuxt-users/[id].get")
});
addServerHandler({
route: `${base}/:id`,
method: "patch",
handler: resolver.resolve("./runtime/server/api/nuxt-users/[id].patch")
});
addServerHandler({
route: `${base}/:id`,
method: "delete",
handler: resolver.resolve("./runtime/server/api/nuxt-users/[id].delete")
});
nuxt.hook("nitro:config", async (nitroConfig) => {
nitroConfig.experimental = nitroConfig.experimental || {};
nitroConfig.experimental.database = true;
nitroConfig.database = nitroConfig.database || {};
if (!nitroConfig.database.default) {
const connectorOptions = { ...runtimeConfigOptions.connector.options };
let nitroConnector;
switch (runtimeConfigOptions.connector.name) {
case "sqlite":
nitroConnector = "better-sqlite3";
break;
case "mysql":
nitroConnector = "mysql2";
break;
case "postgresql":
nitroConnector = "postgresql";
break;
default:
nitroConnector = "better-sqlite3";
}
nitroConfig.database.default = {
connector: nitroConnector,
options: connectorOptions
};
}
nitroConfig.experimental.tasks = true;
nitroConfig.scanDirs = nitroConfig.scanDirs || [];
nitroConfig.scanDirs.push(resolver.resolve("./runtime/server/tasks"));
});
addComponent({
name: "NUsersLoginForm",
filePath: resolver.resolve("./runtime/components/NUsersLoginForm.vue")
});
addComponent({
name: "NUsersLogoutLink",
filePath: resolver.resolve("./runtime/components/NUsersLogoutLink.vue")
});
addComponent({
name: "NUsersProfileInfo",
filePath: resolver.resolve("./runtime/components/NUsersProfileInfo.vue")
});
addComponent({
name: "NUsersResetPasswordForm",
filePath: resolver.resolve("./runtime/components/NUsersResetPasswordForm.vue")
});
addComponent({
name: "NUsersPasswordStrengthIndicator",
filePath: resolver.resolve("./runtime/components/NUsersPasswordStrengthIndicator.vue")
});
addComponent({
name: "NUsersList",
filePath: resolver.resolve("./runtime/components/NUsersList.vue")
});
addComponent({
name: "NUsersUserCard",
filePath: resolver.resolve("./runtime/components/NUsersUserCard.vue")
});
addComponent({
name: "NUsersUserForm",
filePath: resolver.resolve("./runtime/components/NUsersUserForm.vue")
});
nuxt.options.css = nuxt.options.css || [];
nuxt.options.css.push(resolver.resolve("./runtime/assets/nuxt-users.css"));
}
});
export { module as default, defaultOptions };