@axium/server 0.7.6 → 0.8.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/dist/apps.d.ts +15 -0
- package/dist/apps.js +20 -0
- package/dist/auth.d.ts +63 -30
- package/dist/auth.js +110 -129
- package/dist/cli.js +33 -6
- package/dist/config.d.ts +241 -61
- package/dist/config.js +26 -2
- package/dist/database.d.ts +28 -37
- package/dist/database.js +124 -50
- package/dist/io.js +6 -2
- package/dist/plugins.d.ts +7 -24
- package/dist/plugins.js +9 -14
- package/dist/routes.d.ts +55 -0
- package/dist/routes.js +54 -0
- package/package.json +7 -15
- package/web/api/index.ts +7 -0
- package/web/api/metadata.ts +35 -0
- package/web/api/passkeys.ts +56 -0
- package/web/api/readme.md +1 -0
- package/web/api/register.ts +83 -0
- package/web/api/schemas.ts +22 -0
- package/web/api/session.ts +33 -0
- package/web/api/users.ts +340 -0
- package/web/api/utils.ts +66 -0
- package/web/auth.ts +1 -5
- package/web/hooks.server.ts +6 -1
- package/web/index.server.ts +0 -1
- package/web/lib/Dialog.svelte +3 -6
- package/web/lib/FormDialog.svelte +53 -14
- package/web/lib/Toast.svelte +8 -1
- package/web/lib/UserCard.svelte +1 -1
- package/web/lib/auth.ts +12 -0
- package/web/lib/icons/Icon.svelte +5 -7
- package/web/lib/index.ts +0 -2
- package/web/lib/styles.css +12 -1
- package/web/routes/+layout.svelte +1 -1
- package/web/routes/[...path]/+page.server.ts +13 -0
- package/web/routes/[appId]/[...page]/+page.server.ts +14 -0
- package/web/routes/_axium/default/+page.svelte +11 -0
- package/web/routes/account/+page.svelte +224 -0
- package/web/routes/api/[...path]/+server.ts +49 -0
- package/web/routes/login/+page.svelte +25 -0
- package/web/routes/logout/+page.svelte +13 -0
- package/web/routes/register/+page.svelte +21 -0
- package/web/tsconfig.json +2 -1
- package/web/utils.ts +9 -15
- package/web/actions.ts +0 -58
- package/web/lib/Account.svelte +0 -76
- package/web/lib/SignUp.svelte +0 -20
- package/web/lib/account.css +0 -36
- package/web/routes/+page.server.ts +0 -16
- package/web/routes/+page.svelte +0 -10
- package/web/routes/name/+page.server.ts +0 -5
- package/web/routes/name/+page.svelte +0 -20
- package/web/routes/signup/+page.server.ts +0 -10
- package/web/routes/signup/+page.svelte +0 -15
package/dist/apps.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { LoadEvent, RequestEvent } from '@sveltejs/kit';
|
|
2
|
+
import type { WebRoute, WebRouteOptions } from './routes.js';
|
|
3
|
+
export interface CreateAppOptions {
|
|
4
|
+
id: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const apps: Map<string, App>;
|
|
8
|
+
export declare class App {
|
|
9
|
+
readonly id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
protected readonly routes: Map<string, WebRoute>;
|
|
12
|
+
constructor(opt: CreateAppOptions);
|
|
13
|
+
addRoute(route: WebRouteOptions): void;
|
|
14
|
+
resolveRoute(event: RequestEvent | LoadEvent): WebRoute | undefined;
|
|
15
|
+
}
|
package/dist/apps.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { pick } from 'utilium';
|
|
2
|
+
import { addRoute, resolveRoute } from './routes.js';
|
|
3
|
+
export const apps = new Map();
|
|
4
|
+
export class App {
|
|
5
|
+
id;
|
|
6
|
+
name;
|
|
7
|
+
routes = new Map();
|
|
8
|
+
constructor(opt) {
|
|
9
|
+
if (apps.has(opt.id))
|
|
10
|
+
throw new ReferenceError(`App with ID "${opt.id}" already exists.`);
|
|
11
|
+
Object.assign(this, pick(opt, 'id', 'name'));
|
|
12
|
+
apps.set(this.id, this);
|
|
13
|
+
}
|
|
14
|
+
addRoute(route) {
|
|
15
|
+
addRoute(route, this.routes);
|
|
16
|
+
}
|
|
17
|
+
resolveRoute(event) {
|
|
18
|
+
return resolveRoute(event, this.routes);
|
|
19
|
+
}
|
|
20
|
+
}
|
package/dist/auth.d.ts
CHANGED
|
@@ -1,35 +1,68 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* User preferences.
|
|
7
|
-
* Modify with `declare module ...`
|
|
8
|
-
*/
|
|
9
|
-
export interface Preferences {
|
|
1
|
+
import type { Passkey, Session, Verification } from '@axium/core/api';
|
|
2
|
+
import type { User } from '@axium/core/user';
|
|
3
|
+
export interface UserInternal extends User {
|
|
4
|
+
password?: string | null;
|
|
5
|
+
salt?: string | null;
|
|
10
6
|
}
|
|
11
|
-
declare
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
export declare function getUser(id: string): Promise<{
|
|
8
|
+
name: string;
|
|
9
|
+
id: string;
|
|
10
|
+
image: string | null | undefined;
|
|
11
|
+
email: string;
|
|
12
|
+
emailVerified: Date | null | undefined;
|
|
13
|
+
preferences: import("@axium/core/user").Preferences | undefined;
|
|
14
|
+
} | null>;
|
|
15
|
+
export declare function getUserByEmail(email: string): Promise<{
|
|
16
|
+
name: string;
|
|
17
|
+
id: string;
|
|
18
|
+
image: string | null | undefined;
|
|
19
|
+
email: string;
|
|
20
|
+
emailVerified: Date | null | undefined;
|
|
21
|
+
preferences: import("@axium/core/user").Preferences | undefined;
|
|
22
|
+
} | null>;
|
|
23
|
+
export declare function updateUser({ id, ...user }: UserInternal): Promise<{
|
|
24
|
+
name: string;
|
|
25
|
+
id: string;
|
|
26
|
+
image: string | null | undefined;
|
|
27
|
+
email: string;
|
|
28
|
+
emailVerified: Date | null | undefined;
|
|
29
|
+
preferences: import("@axium/core/user").Preferences | undefined;
|
|
30
|
+
}>;
|
|
31
|
+
export interface SessionInternal extends Session {
|
|
32
|
+
token: string;
|
|
33
|
+
elevated: boolean;
|
|
17
34
|
}
|
|
18
|
-
export declare
|
|
19
|
-
export declare function
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
export declare function
|
|
24
|
-
|
|
25
|
-
|
|
35
|
+
export declare function createSession(userId: string, elevated?: boolean): Promise<SessionInternal>;
|
|
36
|
+
export declare function checkExpiration(session: SessionInternal): Promise<void>;
|
|
37
|
+
export declare function getSessionAndUser(token: string): Promise<SessionInternal & {
|
|
38
|
+
user: UserInternal | null;
|
|
39
|
+
}>;
|
|
40
|
+
export declare function getSession(sessionId: string): Promise<SessionInternal>;
|
|
41
|
+
export declare function getSessions(userId: string): Promise<SessionInternal[]>;
|
|
42
|
+
export declare function updateSession(session: SessionInternal): Promise<{
|
|
43
|
+
id: string;
|
|
44
|
+
expires: Date;
|
|
45
|
+
token: string;
|
|
46
|
+
userId: string;
|
|
47
|
+
created: Date;
|
|
48
|
+
elevated: boolean;
|
|
26
49
|
}>;
|
|
50
|
+
export type VerificationRole = 'verify_email' | 'login';
|
|
51
|
+
export interface VerificationInternal extends Verification {
|
|
52
|
+
token: string;
|
|
53
|
+
role: VerificationRole;
|
|
54
|
+
}
|
|
27
55
|
/**
|
|
28
|
-
*
|
|
56
|
+
* Create a verification
|
|
57
|
+
* @param expires How long the token should be valid for in seconds
|
|
29
58
|
*/
|
|
30
|
-
export declare function
|
|
31
|
-
|
|
32
|
-
export
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
59
|
+
export declare function createVerification(role: VerificationRole, userId: string, expires: number): Promise<VerificationInternal>;
|
|
60
|
+
export declare function useVerification(role: VerificationRole, userId: string, token: string): Promise<VerificationInternal | undefined>;
|
|
61
|
+
export interface PasskeyInternal extends Passkey {
|
|
62
|
+
publicKey: Uint8Array;
|
|
63
|
+
counter: number;
|
|
64
|
+
}
|
|
65
|
+
export declare function getPasskey(id: string): Promise<PasskeyInternal | null>;
|
|
66
|
+
export declare function createPasskey(passkey: Omit<PasskeyInternal, 'createdAt'>): Promise<PasskeyInternal>;
|
|
67
|
+
export declare function getPasskeysByUserId(userId: string): Promise<PasskeyInternal[]>;
|
|
68
|
+
export declare function updatePasskeyCounter(id: PasskeyInternal['id'], newCounter: PasskeyInternal['counter']): Promise<PasskeyInternal>;
|
package/dist/auth.js
CHANGED
|
@@ -1,137 +1,118 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (
|
|
1
|
+
import { jsonObjectFrom } from 'kysely/helpers/postgres';
|
|
2
|
+
import { randomBytes, randomUUID } from 'node:crypto';
|
|
3
|
+
import { connect, database as db } from './database.js';
|
|
4
|
+
export async function getUser(id) {
|
|
5
|
+
connect();
|
|
6
|
+
const result = await db.selectFrom('users').selectAll().where('id', '=', id).executeTakeFirst();
|
|
7
|
+
if (!result)
|
|
8
|
+
return null;
|
|
9
|
+
return result;
|
|
10
|
+
}
|
|
11
|
+
export async function getUserByEmail(email) {
|
|
12
|
+
connect();
|
|
13
|
+
const result = await db.selectFrom('users').selectAll().where('email', '=', email).executeTakeFirst();
|
|
14
|
+
if (!result)
|
|
15
|
+
return null;
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
export async function updateUser({ id, ...user }) {
|
|
19
|
+
connect();
|
|
20
|
+
const query = db.updateTable('users').set(user).where('id', '=', id);
|
|
21
|
+
return await query.returningAll().executeTakeFirstOrThrow();
|
|
22
|
+
}
|
|
23
|
+
const in30days = () => new Date(Date.now() + 2592000000);
|
|
24
|
+
const in10minutes = () => new Date(Date.now() + 600000);
|
|
25
|
+
export async function createSession(userId, elevated = false) {
|
|
26
|
+
connect();
|
|
27
|
+
const session = {
|
|
28
|
+
id: randomUUID(),
|
|
29
|
+
userId,
|
|
30
|
+
token: randomBytes(64).toString('base64'),
|
|
31
|
+
expires: elevated ? in10minutes() : in30days(),
|
|
32
|
+
elevated,
|
|
33
|
+
created: new Date(),
|
|
34
|
+
};
|
|
35
|
+
await db.insertInto('sessions').values(session).execute();
|
|
36
|
+
return session;
|
|
37
|
+
}
|
|
38
|
+
export async function checkExpiration(session) {
|
|
39
|
+
if (session.expires.getTime() > Date.now())
|
|
15
40
|
return;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
async getAccount(providerAccountId, provider) {
|
|
19
|
-
const result = await conn.selectFrom('Account').selectAll().where('providerAccountId', '=', providerAccountId).where('provider', '=', provider).executeTakeFirst();
|
|
20
|
-
return result ?? null;
|
|
21
|
-
},
|
|
22
|
-
async getAuthenticator(credentialID) {
|
|
23
|
-
const result = await conn.selectFrom('Authenticator').selectAll().where('credentialID', '=', credentialID).executeTakeFirst();
|
|
24
|
-
return result ?? null;
|
|
25
|
-
},
|
|
26
|
-
async createAuthenticator(authenticator) {
|
|
27
|
-
await conn.insertInto('Authenticator').values(authenticator).executeTakeFirstOrThrow();
|
|
28
|
-
return authenticator;
|
|
29
|
-
},
|
|
30
|
-
async listAuthenticatorsByUserId(userId) {
|
|
31
|
-
const result = await conn.selectFrom('Authenticator').selectAll().where('userId', '=', userId).execute();
|
|
32
|
-
return result;
|
|
33
|
-
},
|
|
34
|
-
async updateAuthenticatorCounter(credentialID, newCounter) {
|
|
35
|
-
await conn.updateTable('Authenticator').set({ counter: newCounter }).where('credentialID', '=', credentialID).executeTakeFirstOrThrow();
|
|
36
|
-
const authenticator = await adapter.getAuthenticator?.(credentialID);
|
|
37
|
-
if (!authenticator)
|
|
38
|
-
throw new Error('Authenticator not found');
|
|
39
|
-
return authenticator;
|
|
40
|
-
},
|
|
41
|
-
});
|
|
41
|
+
await db.deleteFrom('sessions').where('sessions.id', '=', session.id).executeTakeFirstOrThrow();
|
|
42
|
+
throw new Error('Session expired');
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
});
|
|
71
|
-
return { user, session };
|
|
44
|
+
export async function getSessionAndUser(token) {
|
|
45
|
+
connect();
|
|
46
|
+
const result = await db
|
|
47
|
+
.selectFrom('sessions')
|
|
48
|
+
.selectAll()
|
|
49
|
+
.select(eb => jsonObjectFrom(eb.selectFrom('users').selectAll().whereRef('users.id', '=', 'sessions.userId')).as('user'))
|
|
50
|
+
.where('sessions.token', '=', token)
|
|
51
|
+
.executeTakeFirst();
|
|
52
|
+
if (!result)
|
|
53
|
+
throw new Error('Session not found');
|
|
54
|
+
await checkExpiration(result);
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
export async function getSession(sessionId) {
|
|
58
|
+
connect();
|
|
59
|
+
const session = await db.selectFrom('sessions').selectAll().where('id', '=', sessionId).executeTakeFirstOrThrow();
|
|
60
|
+
await checkExpiration(session);
|
|
61
|
+
return session;
|
|
62
|
+
}
|
|
63
|
+
export async function getSessions(userId) {
|
|
64
|
+
connect();
|
|
65
|
+
return await db.selectFrom('sessions').selectAll().where('userId', '=', userId).execute();
|
|
66
|
+
}
|
|
67
|
+
export async function updateSession(session) {
|
|
68
|
+
connect();
|
|
69
|
+
const query = db.updateTable('sessions').set(session).where('sessions.token', '=', session.token);
|
|
70
|
+
return await query.returningAll().executeTakeFirstOrThrow();
|
|
72
71
|
}
|
|
73
72
|
/**
|
|
74
|
-
*
|
|
73
|
+
* Create a verification
|
|
74
|
+
* @param expires How long the token should be valid for in seconds
|
|
75
75
|
*/
|
|
76
|
-
export async function
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
76
|
+
export async function createVerification(role, userId, expires) {
|
|
77
|
+
const token = randomBytes(64).toString('base64url');
|
|
78
|
+
const verification = { userId, token, expires: new Date(Date.now() + expires * 1000), role };
|
|
79
|
+
connect();
|
|
80
|
+
await db.insertInto('verifications').values(verification).executeTakeFirstOrThrow();
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
void db.deleteFrom('verifications').where('verifications.token', '=', verification.token).execute();
|
|
83
|
+
}, expires * 1000);
|
|
84
|
+
return verification;
|
|
85
|
+
}
|
|
86
|
+
export async function useVerification(role, userId, token) {
|
|
87
|
+
connect();
|
|
88
|
+
const query = db
|
|
89
|
+
.deleteFrom('verifications')
|
|
90
|
+
.where('verifications.token', '=', token)
|
|
91
|
+
.where('verifications.userId', '=', userId)
|
|
92
|
+
.where('verifications.role', '=', role);
|
|
93
|
+
return await query.returningAll().executeTakeFirst();
|
|
94
|
+
}
|
|
95
|
+
export async function getPasskey(id) {
|
|
96
|
+
connect();
|
|
97
|
+
const result = await db.selectFrom('passkeys').selectAll().where('id', '=', id).executeTakeFirst();
|
|
98
|
+
if (!result)
|
|
84
99
|
return null;
|
|
85
|
-
return
|
|
100
|
+
return result;
|
|
86
101
|
}
|
|
87
|
-
export function
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
debug,
|
|
104
|
-
experimental: { enableWebAuthn: true },
|
|
105
|
-
secret: config.auth.secret,
|
|
106
|
-
useSecureCookies: config.auth.secure_cookies,
|
|
107
|
-
session: { strategy: 'database' },
|
|
108
|
-
logger: {
|
|
109
|
-
error(error) {
|
|
110
|
-
logger.error('[auth] ' + error.message);
|
|
111
|
-
},
|
|
112
|
-
warn(code) {
|
|
113
|
-
switch (code) {
|
|
114
|
-
case 'experimental-webauthn':
|
|
115
|
-
case 'debug-enabled':
|
|
116
|
-
return;
|
|
117
|
-
case 'csrf-disabled':
|
|
118
|
-
logger.warn('CSRF protection is disabled.');
|
|
119
|
-
break;
|
|
120
|
-
case 'env-url-basepath-redundant':
|
|
121
|
-
case 'env-url-basepath-mismatch':
|
|
122
|
-
default:
|
|
123
|
-
logger.warn('[auth] ' + code);
|
|
124
|
-
}
|
|
125
|
-
},
|
|
126
|
-
debug(message, metadata) {
|
|
127
|
-
debug && logger.debug('[auth]', message, metadata ? JSON.stringify(metadata, (k, v) => (k && JSON.stringify(v).length > 100 ? '...' : v)) : '');
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
callbacks: {
|
|
131
|
-
signIn({ user }) {
|
|
132
|
-
logger.info('[auth] signin', user.id ?? '', user.email ? `(${user.email})` : '');
|
|
133
|
-
return true;
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
};
|
|
102
|
+
export async function createPasskey(passkey) {
|
|
103
|
+
connect();
|
|
104
|
+
const result = await db.insertInto('passkeys').values(passkey).returningAll().executeTakeFirstOrThrow();
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
export async function getPasskeysByUserId(userId) {
|
|
108
|
+
connect();
|
|
109
|
+
return await db.selectFrom('passkeys').selectAll().where('userId', '=', userId).execute();
|
|
110
|
+
}
|
|
111
|
+
export async function updatePasskeyCounter(id, newCounter) {
|
|
112
|
+
connect();
|
|
113
|
+
await db.updateTable('passkeys').set({ counter: newCounter }).where('id', '=', id).executeTakeFirstOrThrow();
|
|
114
|
+
const passkey = await getPasskey(id);
|
|
115
|
+
if (!passkey)
|
|
116
|
+
throw new Error('Passkey not found');
|
|
117
|
+
return passkey;
|
|
137
118
|
}
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Argument, Option, program } from 'commander';
|
|
3
|
-
import { randomBytes } from 'node:crypto';
|
|
4
3
|
import { styleText } from 'node:util';
|
|
5
4
|
import { getByString, isJSON, setByString } from 'utilium';
|
|
6
5
|
import $pkg from '../package.json' with { type: 'json' };
|
|
@@ -8,6 +7,7 @@ import config from './config.js';
|
|
|
8
7
|
import * as db from './database.js';
|
|
9
8
|
import { _portActions, _portMethods, exit, handleError, output, restrictedPorts } from './io.js';
|
|
10
9
|
import { loadDefaultPlugins, plugins, pluginText, resolvePlugin } from './plugins.js';
|
|
10
|
+
import { apps } from './apps.js';
|
|
11
11
|
program
|
|
12
12
|
.version($pkg.version)
|
|
13
13
|
.name('axium')
|
|
@@ -25,10 +25,10 @@ program.hook('preAction', async function (_, action) {
|
|
|
25
25
|
opt.force && output.warn('--force: Protections disabled.');
|
|
26
26
|
if (opt.debug === false)
|
|
27
27
|
config.set({ debug: false });
|
|
28
|
-
if (!config.auth.secret) {
|
|
28
|
+
/* if (!config.auth.secret) {
|
|
29
29
|
config.save({ auth: { secret: process.env.AUTH_SECRET || randomBytes(32).toString('base64') } }, true);
|
|
30
30
|
output.debug('Auto-generated a new auth secret');
|
|
31
|
-
}
|
|
31
|
+
} */
|
|
32
32
|
});
|
|
33
33
|
// Options shared by multiple (sub)commands
|
|
34
34
|
const opts = {
|
|
@@ -78,7 +78,7 @@ axiumDB
|
|
|
78
78
|
.action(async (opt) => {
|
|
79
79
|
const stats = await db.status().catch(exit);
|
|
80
80
|
if (!opt.force)
|
|
81
|
-
for (const key of ['users', '
|
|
81
|
+
for (const key of ['users', 'passkeys', 'sessions']) {
|
|
82
82
|
if (stats[key] == 0)
|
|
83
83
|
continue;
|
|
84
84
|
output.warn(`Database has existing ${key}. Use --force if you really want to drop the database.`);
|
|
@@ -94,7 +94,7 @@ axiumDB
|
|
|
94
94
|
.action(async (opt) => {
|
|
95
95
|
const stats = await db.status().catch(exit);
|
|
96
96
|
if (!opt.force)
|
|
97
|
-
for (const key of ['users', '
|
|
97
|
+
for (const key of ['users', 'passkeys', 'sessions']) {
|
|
98
98
|
if (stats[key] == 0)
|
|
99
99
|
continue;
|
|
100
100
|
output.warn(`Database has existing ${key}. Use --force if you really want to wipe the database.`);
|
|
@@ -103,6 +103,12 @@ axiumDB
|
|
|
103
103
|
await db.wipe(opt).catch(exit);
|
|
104
104
|
await db.database.destroy();
|
|
105
105
|
});
|
|
106
|
+
axiumDB
|
|
107
|
+
.command('check')
|
|
108
|
+
.description('Check the structure of the database')
|
|
109
|
+
.action(async (opt) => {
|
|
110
|
+
await db.check(opt).catch(exit);
|
|
111
|
+
});
|
|
106
112
|
const axiumConfig = program
|
|
107
113
|
.command('config')
|
|
108
114
|
.description('Manage the configuration')
|
|
@@ -191,6 +197,27 @@ axiumPlugin
|
|
|
191
197
|
exit(`Can't find a plugin matching "${search}"`);
|
|
192
198
|
console.log(pluginText(plugin));
|
|
193
199
|
});
|
|
200
|
+
const axiumApps = program.command('apps').description('Manage Axium apps').addOption(opts.global);
|
|
201
|
+
axiumApps
|
|
202
|
+
.command('list')
|
|
203
|
+
.alias('ls')
|
|
204
|
+
.description('List apps added by plugins')
|
|
205
|
+
.option('-l, --long', 'use the long listing format')
|
|
206
|
+
.option('-b, --builtin', 'include built-in apps')
|
|
207
|
+
.action((opt) => {
|
|
208
|
+
if (!apps.size) {
|
|
209
|
+
console.log('No apps.');
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (!opt.long) {
|
|
213
|
+
console.log(Array.from(apps.values().map(app => app.name)).join(', '));
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
console.log(styleText('whiteBright', apps.size + ' app(s) loaded:'));
|
|
217
|
+
for (const app of apps.values()) {
|
|
218
|
+
console.log(app.name, styleText('dim', `(${app.id})`));
|
|
219
|
+
}
|
|
220
|
+
});
|
|
194
221
|
program
|
|
195
222
|
.command('status')
|
|
196
223
|
.alias('stats')
|
|
@@ -234,7 +261,7 @@ program
|
|
|
234
261
|
.addOption(opts.force)
|
|
235
262
|
.addOption(opts.host)
|
|
236
263
|
.action(async (opt) => {
|
|
237
|
-
config.save({ auth: { secret: randomBytes(32).toString('base64') } }, true);
|
|
264
|
+
/* config.save({ auth: { secret: randomBytes(32).toString('base64') } }, true); */
|
|
238
265
|
await db.init({ ...opt, skip: opt.dbSkip }).catch(handleError);
|
|
239
266
|
await restrictedPorts({ method: 'node-cap', action: 'enable' }).catch(handleError);
|
|
240
267
|
});
|