nuxt-users 1.1.2 → 1.1.3
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/.vscode/settings.json +18 -0
- package/CHANGELOG.md +112 -0
- package/README.md +0 -2
- package/dist/chunks/better-sqlite3.mjs +45 -0
- package/dist/chunks/mysql2.mjs +49 -0
- package/dist/chunks/postgresql.mjs +58 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.mjs +587 -0
- package/dist/module.d.mts +1 -3
- package/dist/module.d.ts +55 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +11 -81
- package/dist/runtime/assets/colors.css +1 -0
- package/dist/runtime/components/ForgotPasswordForm.vue +1 -1
- package/dist/runtime/components/LoginForm.vue +1 -1
- package/dist/runtime/components/ResetPasswordForm.vue +1 -1
- package/dist/runtime/plugin.js +13 -3
- package/dist/runtime/server/api/login.post.js +1 -1
- package/dist/runtime/server/services/password.js +2 -2
- package/dist/shared/nuxt-users.C9d5M6B1.mjs +31 -0
- package/package.json +28 -12
- package/data/default.sqlite3 +0 -0
- package/dist/runtime/server/utils/create-migrations-table.d.ts +0 -2
- package/dist/runtime/server/utils/create-migrations-table.js +0 -35
- package/dist/runtime/server/utils/create-password-reset-tokens-table.d.ts +0 -2
- package/dist/runtime/server/utils/create-password-reset-tokens-table.js +0 -40
- package/dist/runtime/server/utils/create-personal-access-tokens-table.d.ts +0 -2
- package/dist/runtime/server/utils/create-personal-access-tokens-table.js +0 -56
- package/dist/runtime/server/utils/create-user.d.ts +0 -1
- package/dist/runtime/server/utils/create-user.js +0 -1
- package/dist/runtime/server/utils/create-users-table.d.ts +0 -2
- package/dist/runtime/server/utils/create-users-table.js +0 -44
- package/dist/runtime/server/utils/db.d.ts +0 -8
- package/dist/runtime/server/utils/db.js +0 -61
- package/dist/runtime/server/utils/migrate.d.ts +0 -4
- package/dist/runtime/server/utils/migrate.js +0 -63
- package/dist/runtime/server/utils/user.d.ts +0 -21
- package/dist/runtime/server/utils/user.js +0 -50
- package/src/cli/create-migrations-table.ts +0 -24
- package/src/cli/create-password-reset-tokens-table.ts +0 -24
- package/src/cli/create-personal-access-tokens-table.ts +0 -24
- package/src/cli/create-user.ts +0 -40
- package/src/cli/create-users-table.ts +0 -24
- package/src/cli/main.ts +0 -28
- package/src/cli/migrate.ts +0 -24
- package/src/cli/project-info.ts +0 -45
- package/src/cli/utils.ts +0 -70
package/dist/module.mjs
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
|
-
import { defineNuxtModule, createResolver,
|
|
1
|
+
import { defineNuxtModule, createResolver, addPlugin, addServerHandler, addComponent } from '@nuxt/kit';
|
|
2
2
|
import { defu } from 'defu';
|
|
3
|
-
import { hasAnyUsers, checkUsersTableExists, checkPersonalAccessTokensTableExists, checkPasswordResetTokensTableExists } from '../dist/runtime/server/utils/db.js';
|
|
4
|
-
import { getAppliedMigrations } from '../dist/runtime/server/utils/migrate.js';
|
|
5
|
-
import { promises } from 'node:fs';
|
|
6
|
-
import { dirname } from 'node:path';
|
|
7
3
|
|
|
8
4
|
const defaultOptions = {
|
|
9
5
|
connector: {
|
|
10
6
|
name: "sqlite",
|
|
11
7
|
options: {
|
|
12
|
-
path: "./data/
|
|
8
|
+
path: "./data/users.sqlite3"
|
|
13
9
|
}
|
|
14
10
|
},
|
|
15
11
|
tables: {
|
|
12
|
+
migrations: "migrations",
|
|
16
13
|
users: "users",
|
|
17
14
|
personalAccessTokens: "personal_access_tokens",
|
|
18
15
|
passwordResetTokens: "password_reset_tokens"
|
|
@@ -31,39 +28,6 @@ const defaultOptions = {
|
|
|
31
28
|
defaults: {
|
|
32
29
|
from: '"Nuxt Users Module" <noreply@example.com>'
|
|
33
30
|
}
|
|
34
|
-
},
|
|
35
|
-
passwordResetBaseUrl: "http://localhost:3000",
|
|
36
|
-
// Added
|
|
37
|
-
// Add option to disable database checks during setup
|
|
38
|
-
skipDatabaseChecks: false
|
|
39
|
-
};
|
|
40
|
-
const runWithTimeout = async (operation, timeoutMs = 5e3) => {
|
|
41
|
-
return Promise.race([
|
|
42
|
-
operation(),
|
|
43
|
-
new Promise((resolve) => {
|
|
44
|
-
setTimeout(() => {
|
|
45
|
-
console.warn("[Nuxt Users DB] \u26A0\uFE0F Database operation timed out after", timeoutMs, "ms");
|
|
46
|
-
resolve(null);
|
|
47
|
-
}, timeoutMs);
|
|
48
|
-
})
|
|
49
|
-
]);
|
|
50
|
-
};
|
|
51
|
-
const ensureSqliteDatabaseExists = async (options) => {
|
|
52
|
-
if (options.connector?.name === "sqlite" && options.connector.options.path) {
|
|
53
|
-
const dbPath = options.connector.options.path;
|
|
54
|
-
try {
|
|
55
|
-
await promises.access(dbPath);
|
|
56
|
-
console.log(`[Nuxt Users DB] \u2139\uFE0F SQLite database exists: ${dbPath}`);
|
|
57
|
-
} catch {
|
|
58
|
-
try {
|
|
59
|
-
const dbDir = dirname(dbPath);
|
|
60
|
-
await promises.mkdir(dbDir, { recursive: true });
|
|
61
|
-
console.log(`[Nuxt Users DB] \u2139\uFE0F Created SQLite database directory: ${dbDir}`);
|
|
62
|
-
console.log(`[Nuxt Users DB] \u2139\uFE0F SQLite database will be created at: ${dbPath}`);
|
|
63
|
-
} catch (error) {
|
|
64
|
-
console.warn(`[Nuxt Users DB] \u26A0\uFE0F Failed to create database directory: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
31
|
}
|
|
68
32
|
};
|
|
69
33
|
const module = defineNuxtModule({
|
|
@@ -75,61 +39,26 @@ const module = defineNuxtModule({
|
|
|
75
39
|
defaults: defaultOptions,
|
|
76
40
|
async setup(options, nuxt) {
|
|
77
41
|
const resolver = createResolver(import.meta.url);
|
|
78
|
-
await ensureSqliteDatabaseExists(options);
|
|
79
|
-
if (!options.skipDatabaseChecks) {
|
|
80
|
-
const appliedMigrations = await runWithTimeout(() => getAppliedMigrations(options)) || [];
|
|
81
|
-
const requiredMigrations = [
|
|
82
|
-
"create_migrations_table",
|
|
83
|
-
"create_users_table",
|
|
84
|
-
"create_personal_access_tokens_table",
|
|
85
|
-
"create_password_reset_tokens_table"
|
|
86
|
-
];
|
|
87
|
-
const missingMigrations = requiredMigrations.filter((migration) => !appliedMigrations.includes(migration));
|
|
88
|
-
if (missingMigrations.length > 0) {
|
|
89
|
-
console.warn(`[Nuxt Users DB] \u26A0\uFE0F Missing migrations: ${missingMigrations.join(", ")}`);
|
|
90
|
-
console.warn("[Nuxt Users DB] \u26A0\uFE0F Run migrations with: npx nuxt-users-migrate");
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
42
|
const runtimeConfigOptions = defu(options, nuxt.options.runtimeConfig.nuxtUsers || {}, defaultOptions);
|
|
94
43
|
nuxt.options.runtimeConfig.nuxtUsers = {
|
|
95
44
|
...runtimeConfigOptions,
|
|
96
45
|
tables: {
|
|
46
|
+
migrations: options.tables?.migrations || "migrations",
|
|
97
47
|
users: options.tables?.users || "users",
|
|
98
48
|
personalAccessTokens: options.tables?.personalAccessTokens || "personal_access_tokens",
|
|
99
49
|
passwordResetTokens: options.tables?.passwordResetTokens || "password_reset_tokens"
|
|
100
50
|
}
|
|
101
51
|
};
|
|
102
|
-
let hasUsersTable = false;
|
|
103
|
-
let hasPersonalAccessTokensTable = false;
|
|
104
|
-
let hasPasswordResetTokensTable = false;
|
|
105
|
-
if (!options.skipDatabaseChecks) {
|
|
106
|
-
hasUsersTable = await runWithTimeout(() => checkUsersTableExists(options)) || false;
|
|
107
|
-
if (!hasUsersTable) {
|
|
108
|
-
console.warn("[Nuxt Users DB] \u26A0\uFE0F Users table does not exist, you should run the migration script to create it by running: npx nuxt-users-migrate");
|
|
109
|
-
}
|
|
110
|
-
hasPersonalAccessTokensTable = await runWithTimeout(() => checkPersonalAccessTokensTableExists(options)) || false;
|
|
111
|
-
if (!hasPersonalAccessTokensTable) {
|
|
112
|
-
console.warn("[Nuxt Users DB] \u26A0\uFE0F Personal access tokens table does not exist, you should run the migration script to create it by running: npx nuxt-users-migrate");
|
|
113
|
-
}
|
|
114
|
-
hasPasswordResetTokensTable = await runWithTimeout(() => checkPasswordResetTokensTableExists(options)) || false;
|
|
115
|
-
if (!hasPasswordResetTokensTable) {
|
|
116
|
-
console.warn("[Nuxt Users DB] \u26A0\uFE0F Password reset tokens table does not exist, you should run the migration script to create it by running: npx nuxt-users-migrate");
|
|
117
|
-
}
|
|
118
|
-
const hasUsers = await runWithTimeout(() => hasAnyUsers(options)) || false;
|
|
119
|
-
if (!hasUsers) {
|
|
120
|
-
console.warn('[Nuxt Users DB] \u26A0\uFE0F No users found! Create a default user by running: npx nuxt-users-create-user rrd@example.com "John Doe" mypassword123');
|
|
121
|
-
}
|
|
122
|
-
} else {
|
|
123
|
-
console.log("[Nuxt Users DB] \u2139\uFE0F Skipping database checks during setup");
|
|
124
|
-
}
|
|
125
52
|
nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
|
|
126
53
|
nuxt.options.runtimeConfig.public.nuxtUsers = {
|
|
127
54
|
tables: {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
55
|
+
migrations: options.tables?.migrations,
|
|
56
|
+
users: options.tables?.users,
|
|
57
|
+
personalAccessTokens: options.tables?.personalAccessTokens,
|
|
58
|
+
passwordResetTokens: options.tables?.passwordResetTokens
|
|
131
59
|
}
|
|
132
60
|
};
|
|
61
|
+
addPlugin(resolver.resolve("./runtime/plugin"));
|
|
133
62
|
addServerHandler({
|
|
134
63
|
route: "/api/login",
|
|
135
64
|
method: "post",
|
|
@@ -145,7 +74,6 @@ const module = defineNuxtModule({
|
|
|
145
74
|
method: "post",
|
|
146
75
|
handler: resolver.resolve("./runtime/server/api/auth/reset-password.post")
|
|
147
76
|
});
|
|
148
|
-
addPlugin(resolver.resolve("./runtime/plugin"));
|
|
149
77
|
addComponent({
|
|
150
78
|
name: "LoginForm",
|
|
151
79
|
filePath: resolver.resolve("./runtime/components/LoginForm.vue")
|
|
@@ -158,6 +86,8 @@ const module = defineNuxtModule({
|
|
|
158
86
|
name: "ResetPasswordForm",
|
|
159
87
|
filePath: resolver.resolve("./runtime/components/ResetPasswordForm.vue")
|
|
160
88
|
});
|
|
89
|
+
nuxt.options.css = nuxt.options.css || [];
|
|
90
|
+
nuxt.options.css.push(resolver.resolve("./runtime/assets/colors.css"));
|
|
161
91
|
}
|
|
162
92
|
});
|
|
163
93
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--color-primary:#3b82f6;--color-primary-dark:#2563eb;--color-primary-light:#60a5fa;--color-secondary:#059669;--color-secondary-dark:#047857;--color-secondary-light:#10b981;--color-white:#fff;--color-black:#000;--color-gray-50:#f9fafb;--color-gray-100:#f3f4f6;--color-gray-200:#e5e7eb;--color-gray-300:#d1d5db;--color-gray-400:#9ca3af;--color-gray-500:#6b7280;--color-gray-600:#4b5563;--color-gray-700:#374151;--color-gray-800:#1f2937;--color-gray-900:#111827;--color-success:#059669;--color-success-light:#f0fdf4;--color-warning:#f59e0b;--color-warning-light:#fef3c7;--color-warning-text:#92400e;--color-error:#dc2626;--color-error-light:#fef2f2;--color-error-border:#fecaca;--color-error-alt:#db5050;--color-border:#e5e7eb;--color-border-light:#d1d5db;--color-border-dark:#ccc;--color-bg-primary:#fff;--color-bg-secondary:#f9fafb;--color-bg-tertiary:#f3f4f6}
|
|
@@ -75,5 +75,5 @@ const handleForgotPassword = async (data) => {
|
|
|
75
75
|
</template>
|
|
76
76
|
|
|
77
77
|
<style scoped>
|
|
78
|
-
.error{color:red}.success{color:green}.form-message{font-size:.9rem;margin-top:
|
|
78
|
+
.error{color:red}.success{color:green}.form-message{font-size:.9rem;margin-top:1em}:deep(.formkit-outer){margin-bottom:1em}:deep(.formkit-label){display:block;font-weight:700;margin-bottom:.25em}:deep(.formkit-input input[type=email]),:deep(.formkit-input input[type=password]){border:1px solid var(--color-border-dark);border-radius:4px;box-sizing:border-box;padding:.75em;width:100%}:deep(.formkit-input input[type=submit]){background-color:var(--color-gray-800);border:none;border-radius:4px;color:#fff;cursor:pointer;padding:.75em 1.5em}:deep(.formkit-input input[type=submit]:disabled){background-color:var(--color-gray-500);cursor:not-allowed}:deep(.formkit-messages){list-style:none;margin-top:.25em;padding:0}:deep(.formkit-message){color:red;font-size:.8rem}
|
|
79
79
|
</style>
|
|
@@ -129,5 +129,5 @@ const handleSubmit = async (formData) => {
|
|
|
129
129
|
</template>
|
|
130
130
|
|
|
131
131
|
<style scoped>
|
|
132
|
-
.login-form-container{background
|
|
132
|
+
.login-form-container{background:var(--color-bg-primary);border:1px solid var(--color-border);border-radius:12px;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);margin:0 auto;max-width:400px;padding:2em;width:100%}:deep(.formkit-form){display:flex;flex-direction:column;gap:1.5rem}.login-header{margin-bottom:1em;text-align:center}.login-title{color:var(--color-gray-800);font-size:1.875rem;font-weight:700;line-height:1.2;margin:0 0 .5em}.login-subtitle{color:var(--color-gray-500);font-size:.875rem;line-height:1.5;margin:0}:deep(.formkit-inner){--fk-border-radius:8px;--fk-border-color:var(--color-border-light);--fk-border-color-focus:var(--color-primary);--fk-bg-color:var(--color-bg-secondary);--fk-bg-color-focus:var(--color-bg-primary);--fk-text-color:var(--color-gray-700);--fk-text-color-placeholder:var(--color-gray-400);--fk-font-size:0.875rem;--fk-padding:0.75em 1em;--fk-transition:all 0.2s ease-in-out}:deep(.formkit-inner .formkit-input){background-color:var(--fk-bg-color);border:1px solid var(--fk-border-color);border-radius:var(--fk-border-radius);box-sizing:border-box;color:var(--fk-text-color);font-size:var(--fk-font-size);padding:var(--fk-padding);transition:var(--fk-transition);width:100%}:deep(.formkit-inner .formkit-input:focus){background-color:var(--fk-bg-color-focus);border-color:var(--fk-border-color-focus);box-shadow:0 0 0 3px rgba(59,130,246,.1);outline:none}:deep(.formkit-inner .formkit-label){color:var(--color-gray-700);display:block;font-size:.875rem;font-weight:500;margin-bottom:.5em}:deep(.formkit-messages){font-size:.75rem;list-style:none;padding:0}:deep(.formkit-message){margin-top:.25em}:deep(.formkit-message[data-message-type=validation]){color:var(--color-error-alt)}:deep(.formkit-message[data-message-type=error]){color:var(--color-error)}:deep(.formkit-wrapper:has(input[type=checkbox])){align-items:center;display:flex;gap:.5rem}:deep(.formkit-input[type=checkbox]){margin:0;width:auto}:deep(.formkit-label:has(input[type=checkbox])){color:var(--color-gray-700);font-size:.875rem;margin:0}:deep(button[type=submit]){align-items:center;background-color:var(--color-primary);border:1px solid var(--color-primary);border-radius:8px;color:var(--color-white);cursor:pointer;display:flex;font-size:.875rem;font-weight:500;gap:.5rem;justify-content:center;min-height:44px;padding:.75em 1em;transition:all .2s ease-in-out;width:100%}:deep(button[type=submit]:hover:not(:disabled)){background-color:var(--color-primary-dark);border-color:var(--color-primary-dark)}:deep(button[type=submit]:disabled){cursor:not-allowed;opacity:.6}.loading-spinner{animation:spin 1s linear infinite;border:2px solid var(--color-white);border-radius:50%;border-top:2px solid transparent;height:16px;width:16px}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.login-footer{margin-top:1em;text-align:center}.forgot-password{margin:0}.forgot-link{color:var(--color-primary);font-size:.875rem;text-decoration:none;transition:color .2s ease-in-out}.forgot-link:hover{color:var(--color-primary-dark);text-decoration:underline}.error-message{background-color:var(--color-error-light);border:1px solid var(--color-error-border);border-radius:8px;color:var(--color-error);font-size:.875rem;margin-top:1em;padding:.75em 1em;text-align:center}@media (max-width:480px){.login-form-container{margin:1em;padding:1.5em}.login-title{font-size:1.5rem}}
|
|
133
133
|
</style>
|
|
@@ -119,5 +119,5 @@ const handleResetPassword = async (data) => {
|
|
|
119
119
|
</template>
|
|
120
120
|
|
|
121
121
|
<style scoped>
|
|
122
|
-
.error{color:red}.success{color:green}.form-message{font-size:.9rem;margin-top:
|
|
122
|
+
.error{color:red}.success{color:green}.form-message{font-size:.9rem;margin-top:1em}:deep(.formkit-outer){margin-bottom:1em}:deep(.formkit-label){display:block;font-weight:700;margin-bottom:.25em}:deep(.formkit-input input[type=email]),:deep(.formkit-input input[type=password]){border:1px solid var(--color-border-dark);border-radius:4px;box-sizing:border-box;padding:.75em;width:100%}:deep(.formkit-input input[type=submit]){background-color:var(--color-gray-800);border:none;border-radius:4px;color:#fff;cursor:pointer;padding:.75em 1.5em}:deep(.formkit-input input[type=submit]:disabled){background-color:var(--color-gray-500);cursor:not-allowed}:deep(.formkit-messages){list-style:none;margin-top:.25em;padding:0}:deep(.formkit-message){color:red;font-size:.8rem}
|
|
123
123
|
</style>
|
package/dist/runtime/plugin.js
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
import { defineNuxtPlugin } from "#app";
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { defineNuxtPlugin, useRuntimeConfig } from "#app";
|
|
2
|
+
import { checkTableExists } from "../utils/db";
|
|
3
|
+
export default defineNuxtPlugin(async (_nuxtApp) => {
|
|
4
|
+
if (import.meta.client) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
const { nuxtUsers } = useRuntimeConfig();
|
|
8
|
+
const options = nuxtUsers;
|
|
9
|
+
const hasMigrationsTable = await checkTableExists(options, options.tables.migrations);
|
|
10
|
+
if (!hasMigrationsTable) {
|
|
11
|
+
useRuntimeConfig().public.nuxtUsers.tables.migrations = "";
|
|
12
|
+
console.warn("[Nuxt Users] \u26A0\uFE0F Migrations table does not exist, you should run the migration script to create it by running: npx nuxt-users migrate");
|
|
13
|
+
}
|
|
4
14
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createError, defineEventHandler, readBody, setCookie } from "h3";
|
|
2
|
-
import { useDb } from "../utils/db.js";
|
|
3
2
|
import bcrypt from "bcrypt";
|
|
4
3
|
import crypto from "node:crypto";
|
|
5
4
|
import { useRuntimeConfig } from "#imports";
|
|
5
|
+
import { useDb } from "../../../utils/db";
|
|
6
6
|
export default defineEventHandler(async (event) => {
|
|
7
7
|
const body = await readBody(event);
|
|
8
8
|
const { email, password } = body;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createTransport } from "nodemailer";
|
|
2
2
|
import crypto from "node:crypto";
|
|
3
3
|
import bcrypt from "bcrypt";
|
|
4
|
-
import { findUserByEmail, updateUserPassword } from "
|
|
5
|
-
import { useDb } from "
|
|
4
|
+
import { findUserByEmail, updateUserPassword } from "../../../utils/user";
|
|
5
|
+
import { useDb } from "../../../utils/db";
|
|
6
6
|
const TOKEN_EXPIRATION_HOURS = 1;
|
|
7
7
|
export const sendPasswordResetLink = async (email, options) => {
|
|
8
8
|
const user = await findUserByEmail(email, options);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class BoundableStatement {
|
|
2
|
+
_statement;
|
|
3
|
+
constructor(rawStmt) {
|
|
4
|
+
this._statement = rawStmt;
|
|
5
|
+
}
|
|
6
|
+
bind(...params) {
|
|
7
|
+
return new BoundStatement(this, params);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
class BoundStatement {
|
|
11
|
+
#statement;
|
|
12
|
+
#params;
|
|
13
|
+
constructor(statement, params) {
|
|
14
|
+
this.#statement = statement;
|
|
15
|
+
this.#params = params;
|
|
16
|
+
}
|
|
17
|
+
bind(...params) {
|
|
18
|
+
return new BoundStatement(this.#statement, params);
|
|
19
|
+
}
|
|
20
|
+
all() {
|
|
21
|
+
return this.#statement.all(...this.#params);
|
|
22
|
+
}
|
|
23
|
+
run() {
|
|
24
|
+
return this.#statement.run(...this.#params);
|
|
25
|
+
}
|
|
26
|
+
get() {
|
|
27
|
+
return this.#statement.get(...this.#params);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { BoundableStatement as B };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-users",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "Nuxt users module",
|
|
5
5
|
"repository": "rrd108/nuxt-users",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,21 +20,34 @@
|
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
23
|
-
"dist"
|
|
24
|
-
"src/cli",
|
|
25
|
-
"data"
|
|
23
|
+
"dist"
|
|
26
24
|
],
|
|
27
25
|
"bin": {
|
|
28
|
-
"nuxt-users": "./
|
|
26
|
+
"nuxt-users": "./dist/cli.mjs"
|
|
27
|
+
},
|
|
28
|
+
"unbuild": {
|
|
29
|
+
"entries": [
|
|
30
|
+
"./src/module",
|
|
31
|
+
{
|
|
32
|
+
"builder": "rollup",
|
|
33
|
+
"input": "./src/cli/main",
|
|
34
|
+
"name": "cli",
|
|
35
|
+
"ext": "mjs"
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"declaration": true,
|
|
39
|
+
"clean": true,
|
|
40
|
+
"failOnWarn": false
|
|
29
41
|
},
|
|
30
42
|
"scripts": {
|
|
31
|
-
"prepack": "
|
|
43
|
+
"prepack": "nuxt-module-build build",
|
|
44
|
+
"postinstall": "node -e \"try { require('fs').chmodSync('./dist/cli.mjs', '755') } catch(e) {}\"",
|
|
32
45
|
"predev": "node -v | grep -q 'v22' || (echo 'Please use Node.js v22 for deployment' && exit 1)",
|
|
33
|
-
"dev": "
|
|
46
|
+
"dev": "yarn dev:prepare && nuxi dev playground",
|
|
34
47
|
"dev:build": "nuxi build playground",
|
|
35
48
|
"dev:prepare": "yarn nuxt-module-build build --stub && yarn nuxt-module-build prepare && nuxi prepare playground",
|
|
36
49
|
"prerelease": "node -v | grep -q 'v22' || (echo 'Please use Node.js v22 for deployment' && exit 1)",
|
|
37
|
-
"release": "
|
|
50
|
+
"release": "yarn lint && yarn test && yarn prepack && changelogen --release && yarn publish && git push --follow-tags",
|
|
38
51
|
"lint": "eslint .",
|
|
39
52
|
"lint:fix": "eslint . --fix",
|
|
40
53
|
"pretest": "node -v | grep -q 'v22' || (echo 'Please use Node.js v22 for deployment' && exit 1)",
|
|
@@ -54,12 +67,9 @@
|
|
|
54
67
|
"docs:dev": "vitepress dev docs",
|
|
55
68
|
"docs:build": "vitepress build docs",
|
|
56
69
|
"docs:preview": "vitepress preview docs",
|
|
57
|
-
"docs:deploy": "
|
|
70
|
+
"docs:deploy": "yarn docs:build && ./scripts/deploy-docs.sh"
|
|
58
71
|
},
|
|
59
72
|
"dependencies": {
|
|
60
|
-
"@nuxt/kit": "^3.17.6",
|
|
61
|
-
"@types/bcrypt": "^5.0.2",
|
|
62
|
-
"@types/pg": "^8.15.4",
|
|
63
73
|
"bcrypt": "^6.0.0",
|
|
64
74
|
"better-sqlite3": "^12.2.0",
|
|
65
75
|
"citty": "^0.1.6",
|
|
@@ -68,15 +78,21 @@
|
|
|
68
78
|
"nodemailer": "^7.0.5",
|
|
69
79
|
"pg": "^8.16.3"
|
|
70
80
|
},
|
|
81
|
+
"peerDependencies": {
|
|
82
|
+
"@nuxt/kit": "^3.17.6"
|
|
83
|
+
},
|
|
71
84
|
"devDependencies": {
|
|
72
85
|
"@formkit/nuxt": "^1.6.9",
|
|
73
86
|
"@nuxt/devtools": "^2.6.2",
|
|
74
87
|
"@nuxt/eslint-config": "^1.5.2",
|
|
88
|
+
"@nuxt/kit": "^3.17.6",
|
|
75
89
|
"@nuxt/module-builder": "^1.0.1",
|
|
76
90
|
"@nuxt/schema": "^3.17.6",
|
|
77
91
|
"@nuxt/test-utils": "^3.19.2",
|
|
92
|
+
"@types/bcrypt": "^5.0.2",
|
|
78
93
|
"@types/node": "latest",
|
|
79
94
|
"@types/nodemailer": "^6.4.17",
|
|
95
|
+
"@types/pg": "^8.15.4",
|
|
80
96
|
"changelogen": "^0.6.2",
|
|
81
97
|
"eslint": "^9.30.1",
|
|
82
98
|
"nuxt": "^3.17.6",
|
package/data/default.sqlite3
DELETED
|
Binary file
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { useDb } from "./db.js";
|
|
2
|
-
export const createMigrationsTable = async (options) => {
|
|
3
|
-
const connectorName = options.connector.name;
|
|
4
|
-
const db = await useDb(options);
|
|
5
|
-
const tableName = "migrations";
|
|
6
|
-
console.log(`[DB:Create Migrations ${connectorName} Table] Creating ${tableName} table with ${connectorName} connector...`);
|
|
7
|
-
if (connectorName === "sqlite") {
|
|
8
|
-
await db.sql`
|
|
9
|
-
CREATE TABLE IF NOT EXISTS {${tableName}} (
|
|
10
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
11
|
-
name TEXT NOT NULL UNIQUE,
|
|
12
|
-
executed_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
13
|
-
)
|
|
14
|
-
`;
|
|
15
|
-
}
|
|
16
|
-
if (connectorName === "mysql") {
|
|
17
|
-
await db.sql`
|
|
18
|
-
CREATE TABLE IF NOT EXISTS {${tableName}} (
|
|
19
|
-
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
20
|
-
name VARCHAR(255) NOT NULL UNIQUE,
|
|
21
|
-
executed_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
22
|
-
)
|
|
23
|
-
`;
|
|
24
|
-
}
|
|
25
|
-
if (connectorName === "postgresql") {
|
|
26
|
-
await db.sql`
|
|
27
|
-
CREATE TABLE IF NOT EXISTS {${tableName}} (
|
|
28
|
-
id SERIAL PRIMARY KEY,
|
|
29
|
-
name VARCHAR(255) NOT NULL UNIQUE,
|
|
30
|
-
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
31
|
-
)
|
|
32
|
-
`;
|
|
33
|
-
}
|
|
34
|
-
console.log(`[DB:Create Migrations ${connectorName} Table] successfull \u2705`);
|
|
35
|
-
};
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { useDb } from "./db.js";
|
|
2
|
-
export const createPasswordResetTokensTable = async (options) => {
|
|
3
|
-
const connectorName = options.connector.name;
|
|
4
|
-
const db = await useDb(options);
|
|
5
|
-
const tableName = options.tables.passwordResetTokens;
|
|
6
|
-
console.log(`[DB:Create Password Reset Tokens ${connectorName} Table] Creating ${tableName} table with ${connectorName} connector...`);
|
|
7
|
-
if (connectorName === "sqlite") {
|
|
8
|
-
await db.sql`
|
|
9
|
-
CREATE TABLE IF NOT EXISTS {${tableName}} (
|
|
10
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
11
|
-
email TEXT NOT NULL,
|
|
12
|
-
token TEXT NOT NULL UNIQUE,
|
|
13
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
14
|
-
)
|
|
15
|
-
`;
|
|
16
|
-
}
|
|
17
|
-
if (connectorName === "mysql") {
|
|
18
|
-
await db.sql`
|
|
19
|
-
CREATE TABLE IF NOT EXISTS {${tableName}} (
|
|
20
|
-
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
21
|
-
email VARCHAR(255) NOT NULL,
|
|
22
|
-
token VARCHAR(255) NOT NULL UNIQUE,
|
|
23
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
24
|
-
)
|
|
25
|
-
`;
|
|
26
|
-
}
|
|
27
|
-
if (connectorName === "postgresql") {
|
|
28
|
-
await db.sql`
|
|
29
|
-
CREATE TABLE IF NOT EXISTS {${tableName}} (
|
|
30
|
-
id SERIAL PRIMARY KEY,
|
|
31
|
-
email VARCHAR(255) NOT NULL,
|
|
32
|
-
token VARCHAR(255) NOT NULL UNIQUE,
|
|
33
|
-
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
34
|
-
)
|
|
35
|
-
`;
|
|
36
|
-
}
|
|
37
|
-
await db.sql`CREATE INDEX IF NOT EXISTS idx_password_reset_tokens_email ON {${tableName}} (email)`;
|
|
38
|
-
await db.sql`CREATE INDEX IF NOT EXISTS idx_password_reset_tokens_token ON {${tableName}} (token)`;
|
|
39
|
-
console.log(`[DB:Create Password Reset Tokens ${connectorName} Table] Fields: id, email, token, created_at \u2705`);
|
|
40
|
-
};
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { useDb } from "./db.js";
|
|
2
|
-
export const createPersonalAccessTokensTable = async (options) => {
|
|
3
|
-
const connectorName = options.connector.name;
|
|
4
|
-
const db = await useDb(options);
|
|
5
|
-
const tableName = options.tables.personalAccessTokens;
|
|
6
|
-
console.log(`[DB:Create Personal Access Tokens ${connectorName} Table] Creating ${tableName} table with ${connectorName} connector...`);
|
|
7
|
-
if (connectorName === "sqlite") {
|
|
8
|
-
await db.sql`
|
|
9
|
-
CREATE TABLE IF NOT EXISTS {${tableName}} (
|
|
10
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
11
|
-
tokenable_type TEXT NOT NULL,
|
|
12
|
-
tokenable_id INTEGER NOT NULL,
|
|
13
|
-
name TEXT NOT NULL,
|
|
14
|
-
token TEXT NOT NULL UNIQUE,
|
|
15
|
-
abilities TEXT,
|
|
16
|
-
last_used_at DATETIME,
|
|
17
|
-
expires_at DATETIME,
|
|
18
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
19
|
-
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
20
|
-
)
|
|
21
|
-
`;
|
|
22
|
-
}
|
|
23
|
-
if (connectorName === "mysql") {
|
|
24
|
-
await db.sql`
|
|
25
|
-
CREATE TABLE IF NOT EXISTS {${tableName}} (
|
|
26
|
-
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
27
|
-
tokenable_type VARCHAR(255) NOT NULL,
|
|
28
|
-
tokenable_id INT NOT NULL,
|
|
29
|
-
name VARCHAR(255) NOT NULL,
|
|
30
|
-
token VARCHAR(255) NOT NULL UNIQUE,
|
|
31
|
-
abilities TEXT,
|
|
32
|
-
last_used_at DATETIME,
|
|
33
|
-
expires_at DATETIME,
|
|
34
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
35
|
-
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
36
|
-
)
|
|
37
|
-
`;
|
|
38
|
-
}
|
|
39
|
-
if (connectorName === "postgresql") {
|
|
40
|
-
await db.sql`
|
|
41
|
-
CREATE TABLE IF NOT EXISTS {${tableName}} (
|
|
42
|
-
id SERIAL PRIMARY KEY,
|
|
43
|
-
tokenable_type VARCHAR(255) NOT NULL,
|
|
44
|
-
tokenable_id INT NOT NULL,
|
|
45
|
-
name VARCHAR(255) NOT NULL,
|
|
46
|
-
token VARCHAR(255) NOT NULL UNIQUE,
|
|
47
|
-
abilities TEXT,
|
|
48
|
-
last_used_at TIMESTAMPTZ,
|
|
49
|
-
expires_at TIMESTAMPTZ,
|
|
50
|
-
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
51
|
-
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
52
|
-
)
|
|
53
|
-
`;
|
|
54
|
-
}
|
|
55
|
-
console.log(`[DB:Create Personal Access Tokens ${connectorName} Table] Fields: id, tokenable_type, tokenable_id, name, token, abilities, last_used_at, expires_at, created_at, updated_at \u2705`);
|
|
56
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { createUser } from './user.js';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { createUser } from "./user.js";
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { useDb } from "./db.js";
|
|
2
|
-
export const createUsersTable = async (options) => {
|
|
3
|
-
const connectorName = options.connector.name;
|
|
4
|
-
const db = await useDb(options);
|
|
5
|
-
const tableName = options.tables.users;
|
|
6
|
-
console.log(`[DB:Create ${connectorName} Users Table] Creating ${tableName}...`);
|
|
7
|
-
if (connectorName === "sqlite") {
|
|
8
|
-
await db.sql`
|
|
9
|
-
CREATE TABLE IF NOT EXISTS {${tableName}} (
|
|
10
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
11
|
-
email TEXT NOT NULL UNIQUE,
|
|
12
|
-
name TEXT NOT NULL,
|
|
13
|
-
password TEXT NOT NULL,
|
|
14
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
15
|
-
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
16
|
-
)
|
|
17
|
-
`;
|
|
18
|
-
}
|
|
19
|
-
if (connectorName === "mysql") {
|
|
20
|
-
await db.sql`
|
|
21
|
-
CREATE TABLE IF NOT EXISTS {${tableName}} (
|
|
22
|
-
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
23
|
-
email VARCHAR(255) NOT NULL UNIQUE,
|
|
24
|
-
name VARCHAR(255) NOT NULL,
|
|
25
|
-
password VARCHAR(255) NOT NULL,
|
|
26
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
27
|
-
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
28
|
-
)
|
|
29
|
-
`;
|
|
30
|
-
}
|
|
31
|
-
if (connectorName === "postgresql") {
|
|
32
|
-
await db.sql`
|
|
33
|
-
CREATE TABLE IF NOT EXISTS {${tableName}} (
|
|
34
|
-
id SERIAL PRIMARY KEY,
|
|
35
|
-
email VARCHAR(255) NOT NULL UNIQUE,
|
|
36
|
-
name VARCHAR(255) NOT NULL,
|
|
37
|
-
password VARCHAR(255) NOT NULL,
|
|
38
|
-
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
39
|
-
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
40
|
-
)
|
|
41
|
-
`;
|
|
42
|
-
}
|
|
43
|
-
console.log(`[DB:Create ${connectorName} Users Table] Fields: id, email, name, password, created_at, updated_at \u2705`);
|
|
44
|
-
};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { ModuleOptions } from '../../../types.js';
|
|
2
|
-
export declare const getConnector: (name: string) => Promise<typeof import("db0/connectors/mysql2").default | typeof import("db0/connectors/postgresql").default | typeof import("db0/connectors/better-sqlite3").default>;
|
|
3
|
-
export declare const useDb: (options: ModuleOptions) => Promise<import("db0").Database<import("db0").Connector<Database.Database>>>;
|
|
4
|
-
export declare const checkPasswordResetTokensTableExists: (options: ModuleOptions) => Promise<boolean>;
|
|
5
|
-
export declare const checkUsersTableExists: (options: ModuleOptions) => Promise<boolean>;
|
|
6
|
-
export declare const checkPersonalAccessTokensTableExists: (options: ModuleOptions) => Promise<boolean>;
|
|
7
|
-
export declare const checkTableExists: (options: ModuleOptions, tableName: string) => Promise<boolean>;
|
|
8
|
-
export declare const hasAnyUsers: (options: ModuleOptions) => Promise<boolean>;
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { createDatabase } from "db0";
|
|
2
|
-
export const getConnector = async (name) => {
|
|
3
|
-
switch (name) {
|
|
4
|
-
case "mysql":
|
|
5
|
-
return (await import("db0/connectors/mysql2")).default;
|
|
6
|
-
case "postgresql":
|
|
7
|
-
return (await import("db0/connectors/postgresql")).default;
|
|
8
|
-
case "sqlite":
|
|
9
|
-
return (await import("db0/connectors/better-sqlite3")).default;
|
|
10
|
-
default:
|
|
11
|
-
throw new Error(`Unsupported database connector: ${name}`);
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
export const useDb = async (options) => {
|
|
15
|
-
const connectorName = options.connector.name;
|
|
16
|
-
const connector = await getConnector(connectorName);
|
|
17
|
-
const connectorOptions = { ...options.connector.options };
|
|
18
|
-
if (connectorName !== "sqlite") {
|
|
19
|
-
delete connectorOptions.path;
|
|
20
|
-
}
|
|
21
|
-
if (connectorName === "mysql") {
|
|
22
|
-
connectorOptions.connectTimeout = 5e3;
|
|
23
|
-
connectorOptions.acquireTimeout = 5e3;
|
|
24
|
-
}
|
|
25
|
-
if (connectorName === "postgresql") {
|
|
26
|
-
connectorOptions.connectionTimeoutMillis = 5e3;
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
return createDatabase(connector(connectorOptions));
|
|
30
|
-
} catch (error) {
|
|
31
|
-
console.warn(`[Nuxt Users DB] \u26A0\uFE0F Failed to connect to ${connectorName} database:`, error instanceof Error ? error.message : "Unknown error");
|
|
32
|
-
throw error;
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
export const checkPasswordResetTokensTableExists = async (options) => {
|
|
36
|
-
return await checkTableExists(options, options.tables.passwordResetTokens);
|
|
37
|
-
};
|
|
38
|
-
export const checkUsersTableExists = async (options) => {
|
|
39
|
-
return await checkTableExists(options, options.tables.users);
|
|
40
|
-
};
|
|
41
|
-
export const checkPersonalAccessTokensTableExists = async (options) => {
|
|
42
|
-
return await checkTableExists(options, options.tables.personalAccessTokens);
|
|
43
|
-
};
|
|
44
|
-
export const checkTableExists = async (options, tableName) => {
|
|
45
|
-
try {
|
|
46
|
-
const db = await useDb(options);
|
|
47
|
-
await db.sql`SELECT 1 FROM {${tableName}} LIMIT 1`;
|
|
48
|
-
return true;
|
|
49
|
-
} catch {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
export const hasAnyUsers = async (options) => {
|
|
54
|
-
try {
|
|
55
|
-
const db = await useDb(options);
|
|
56
|
-
const users = await db.sql`SELECT COUNT(*) as count FROM {${options.tables.users}}`;
|
|
57
|
-
return users.rows?.[0]?.count > 0;
|
|
58
|
-
} catch {
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { ModuleOptions } from '../../../types.js';
|
|
2
|
-
export declare const getAppliedMigrations: (options: ModuleOptions) => Promise<string[]>;
|
|
3
|
-
export declare const markMigrationAsApplied: (options: ModuleOptions, migrationName: string) => Promise<void>;
|
|
4
|
-
export declare const runMigrations: (options: ModuleOptions) => Promise<void>;
|