@axium/server 0.10.0 → 0.11.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/assets/icons/brands.svg +1493 -0
- package/dist/api/register.js +3 -3
- package/dist/api/users.js +2 -2
- package/dist/auth.d.ts +6 -10
- package/dist/cli.js +234 -16
- package/dist/config.d.ts +10 -4
- package/dist/config.js +12 -6
- package/dist/database.d.ts +12 -12
- package/dist/database.js +79 -84
- package/dist/io.d.ts +14 -17
- package/dist/io.js +58 -36
- package/dist/linking.d.ts +10 -0
- package/dist/linking.js +76 -0
- package/dist/plugins.d.ts +25 -11
- package/dist/plugins.js +17 -14
- package/dist/requests.d.ts +6 -3
- package/dist/requests.js +24 -15
- package/dist/sveltekit.js +18 -14
- package/package.json +10 -6
- package/routes/account/+page.svelte +6 -5
- package/svelte.config.js +2 -1
- package/web/lib/Upload.svelte +58 -0
- package/web/lib/icons/index.ts +6 -3
- package/web/lib/icons/mime.json +2 -1
- package/web/tsconfig.json +0 -1
package/dist/api/register.js
CHANGED
|
@@ -34,7 +34,7 @@ async function OPTIONS(event) {
|
|
|
34
34
|
}
|
|
35
35
|
async function POST(event) {
|
|
36
36
|
const { userId, email, name, response } = await parseBody(event, APIUserRegistration);
|
|
37
|
-
const existing = await db.selectFrom('users').selectAll().where('email', '=', email).executeTakeFirst();
|
|
37
|
+
const existing = await db.selectFrom('users').selectAll().where('email', '=', email.toLowerCase()).executeTakeFirst();
|
|
38
38
|
if (existing)
|
|
39
39
|
error(409, { message: 'Email already in use' });
|
|
40
40
|
const expectedChallenge = registrations.get(userId);
|
|
@@ -50,7 +50,7 @@ async function POST(event) {
|
|
|
50
50
|
error(401, { message: 'Verification failed' });
|
|
51
51
|
await db
|
|
52
52
|
.insertInto('users')
|
|
53
|
-
.values({ id: userId, name, email })
|
|
53
|
+
.values({ id: userId, name, email: email.toLowerCase() })
|
|
54
54
|
.executeTakeFirstOrThrow()
|
|
55
55
|
.catch(withError('Failed to create user'));
|
|
56
56
|
await createPasskey({
|
|
@@ -60,7 +60,7 @@ async function POST(event) {
|
|
|
60
60
|
deviceType: registrationInfo.credentialDeviceType,
|
|
61
61
|
backedUp: registrationInfo.credentialBackedUp,
|
|
62
62
|
}).catch(e => error(500, { message: 'Failed to create passkey' + (config.debug ? `: ${e.message}` : '') }));
|
|
63
|
-
return await createSessionData(
|
|
63
|
+
return await createSessionData(userId);
|
|
64
64
|
}
|
|
65
65
|
addRoute({
|
|
66
66
|
path: '/api/register',
|
package/dist/api/users.js
CHANGED
|
@@ -116,11 +116,11 @@ addRoute({
|
|
|
116
116
|
error(401, { message: 'Verification failed' });
|
|
117
117
|
switch (type) {
|
|
118
118
|
case 'login':
|
|
119
|
-
return await createSessionData(
|
|
119
|
+
return await createSessionData(userId);
|
|
120
120
|
case 'action':
|
|
121
121
|
if ((Date.now() - passkey.createdAt.getTime()) / 60_000 < config.auth.passkey_probation)
|
|
122
122
|
error(403, { message: 'You can not authorize sensitive actions with a newly created passkey' });
|
|
123
|
-
return await createSessionData(
|
|
123
|
+
return await createSessionData(userId, true);
|
|
124
124
|
}
|
|
125
125
|
},
|
|
126
126
|
});
|
package/dist/auth.d.ts
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import type { Passkey, Session, Verification } from '@axium/core/api';
|
|
2
2
|
import type { User } from '@axium/core/user';
|
|
3
3
|
import type { RequestEvent } from '@sveltejs/kit';
|
|
4
|
+
import { type Schema } from './database.js';
|
|
5
|
+
import type { Insertable } from 'kysely';
|
|
4
6
|
export interface UserInternal extends User {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
isAdmin: boolean;
|
|
8
|
+
/** Tags are internal, roles are public */
|
|
9
|
+
tags: string[];
|
|
7
10
|
}
|
|
8
11
|
export declare function getUser(id: string): Promise<UserInternal>;
|
|
9
|
-
export declare function updateUser({ id, ...user }:
|
|
10
|
-
id: string;
|
|
11
|
-
name: string;
|
|
12
|
-
email: string;
|
|
13
|
-
emailVerified: Date | null | undefined;
|
|
14
|
-
image: string | null | undefined;
|
|
15
|
-
preferences: import("@axium/core/user").Preferences | undefined;
|
|
16
|
-
}>;
|
|
12
|
+
export declare function updateUser({ id, ...user }: Insertable<Schema['users']>): Promise<UserInternal>;
|
|
17
13
|
export interface SessionInternal extends Session {
|
|
18
14
|
token: string;
|
|
19
15
|
}
|
package/dist/cli.js
CHANGED
|
@@ -51,17 +51,35 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
51
51
|
var e = new Error(message);
|
|
52
52
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
53
53
|
});
|
|
54
|
+
import { formatDateRange } from '@axium/core/format';
|
|
54
55
|
import { Argument, Option, program } from 'commander';
|
|
56
|
+
import { access } from 'node:fs/promises';
|
|
55
57
|
import { join } from 'node:path/posix';
|
|
58
|
+
import { createInterface } from 'node:readline/promises';
|
|
56
59
|
import { styleText } from 'node:util';
|
|
57
60
|
import { getByString, isJSON, setByString } from 'utilium';
|
|
61
|
+
import z from 'zod/v4';
|
|
58
62
|
import $pkg from '../package.json' with { type: 'json' };
|
|
59
63
|
import { apps } from './apps.js';
|
|
60
64
|
import config, { configFiles, saveConfigTo } from './config.js';
|
|
61
65
|
import * as db from './database.js';
|
|
62
|
-
import { _portActions, _portMethods,
|
|
66
|
+
import { _portActions, _portMethods, exit, handleError, output, restrictedPorts, setCommandTimeout, warn } from './io.js';
|
|
67
|
+
import { linkRoutes, listRouteLinks, unlinkRoutes } from './linking.js';
|
|
63
68
|
import { getSpecifier, plugins, pluginText, resolvePlugin } from './plugins.js';
|
|
64
69
|
import { serve } from './serve.js';
|
|
70
|
+
function readline() {
|
|
71
|
+
const rl = createInterface({
|
|
72
|
+
input: process.stdin,
|
|
73
|
+
output: process.stdout,
|
|
74
|
+
});
|
|
75
|
+
return Object.assign(rl, {
|
|
76
|
+
[Symbol.dispose]: rl.close.bind(rl),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function userText(user, bold = false) {
|
|
80
|
+
const text = `${user.name} <${user.email}> (${user.id})`;
|
|
81
|
+
return bold ? styleText('bold', text) : text;
|
|
82
|
+
}
|
|
65
83
|
program
|
|
66
84
|
.version($pkg.version)
|
|
67
85
|
.name('axium')
|
|
@@ -89,13 +107,14 @@ const opts = {
|
|
|
89
107
|
}),
|
|
90
108
|
force: new Option('-f, --force', 'force the operation').default(false),
|
|
91
109
|
global: new Option('-g, --global', 'apply the operation globally').default(false),
|
|
110
|
+
timeout: new Option('-t, --timeout <ms>', 'how long to wait for commands to complete.').default('1000').argParser(value => {
|
|
111
|
+
const timeout = parseInt(value);
|
|
112
|
+
if (!Number.isSafeInteger(timeout) || timeout < 0)
|
|
113
|
+
warn('Invalid timeout value, using default.');
|
|
114
|
+
setCommandTimeout(timeout);
|
|
115
|
+
}),
|
|
92
116
|
};
|
|
93
|
-
const axiumDB = program
|
|
94
|
-
.command('db')
|
|
95
|
-
.alias('database')
|
|
96
|
-
.description('Manage the database')
|
|
97
|
-
.option('-t, --timeout <ms>', 'how long to wait for commands to complete.', '1000')
|
|
98
|
-
.addOption(opts.host);
|
|
117
|
+
const axiumDB = program.command('db').alias('database').description('Manage the database').addOption(opts.timeout).addOption(opts.host);
|
|
99
118
|
axiumDB
|
|
100
119
|
.command('init')
|
|
101
120
|
.description('Initialize the database')
|
|
@@ -298,7 +317,7 @@ axiumPlugin
|
|
|
298
317
|
exit(`Can't find a plugin matching "${search}"`);
|
|
299
318
|
const specifier = getSpecifier(plugin);
|
|
300
319
|
const _ = __addDisposableResource(env_4, db.connect(), true);
|
|
301
|
-
await plugin.
|
|
320
|
+
await plugin.hooks.remove?.(opt, db.database);
|
|
302
321
|
for (const [path, data] of configFiles) {
|
|
303
322
|
if (!data.plugins)
|
|
304
323
|
continue;
|
|
@@ -317,6 +336,32 @@ axiumPlugin
|
|
|
317
336
|
await result_4;
|
|
318
337
|
}
|
|
319
338
|
});
|
|
339
|
+
axiumPlugin
|
|
340
|
+
.command('init')
|
|
341
|
+
.alias('setup')
|
|
342
|
+
.alias('install')
|
|
343
|
+
.description('Initialize a plugin. This could include adding tables to the database or linking routes.')
|
|
344
|
+
.addOption(opts.timeout)
|
|
345
|
+
.argument('<plugin>', 'the plugin to initialize')
|
|
346
|
+
.action(async (search, opt) => {
|
|
347
|
+
const env_5 = { stack: [], error: void 0, hasError: false };
|
|
348
|
+
try {
|
|
349
|
+
const plugin = resolvePlugin(search);
|
|
350
|
+
if (!plugin)
|
|
351
|
+
exit(`Can't find a plugin matching "${search}"`);
|
|
352
|
+
const _ = __addDisposableResource(env_5, db.connect(), true);
|
|
353
|
+
await plugin.hooks.db_init?.({ force: false, ...opt, skip: true }, db.database);
|
|
354
|
+
}
|
|
355
|
+
catch (e_5) {
|
|
356
|
+
env_5.error = e_5;
|
|
357
|
+
env_5.hasError = true;
|
|
358
|
+
}
|
|
359
|
+
finally {
|
|
360
|
+
const result_5 = __disposeResources(env_5);
|
|
361
|
+
if (result_5)
|
|
362
|
+
await result_5;
|
|
363
|
+
}
|
|
364
|
+
});
|
|
320
365
|
const axiumApps = program.command('apps').description('Manage Axium apps').addOption(opts.global);
|
|
321
366
|
axiumApps
|
|
322
367
|
.command('list')
|
|
@@ -338,19 +383,178 @@ axiumApps
|
|
|
338
383
|
console.log(app.name, styleText('dim', `(${app.id})`));
|
|
339
384
|
}
|
|
340
385
|
});
|
|
386
|
+
const lookup = new Argument('<user>', 'the UUID or email of the user to operate on').argParser(async (lookup) => {
|
|
387
|
+
const value = await (lookup.includes('@') ? z.email() : z.uuid())
|
|
388
|
+
.parseAsync(lookup.toLowerCase())
|
|
389
|
+
.catch(() => exit('Invalid user ID or email.'));
|
|
390
|
+
db.connect();
|
|
391
|
+
const result = await db.database
|
|
392
|
+
.selectFrom('users')
|
|
393
|
+
.where(value.includes('@') ? 'email' : 'id', '=', value)
|
|
394
|
+
.selectAll()
|
|
395
|
+
.executeTakeFirst();
|
|
396
|
+
if (!result)
|
|
397
|
+
exit('No user with matching ID or email.');
|
|
398
|
+
return result;
|
|
399
|
+
});
|
|
400
|
+
/**
|
|
401
|
+
* Updates an array of strings by adding or removing items.
|
|
402
|
+
* Only returns whether the array was updated and diff text for what actually changed.
|
|
403
|
+
*/
|
|
404
|
+
function diffUpdate(original, add, remove) {
|
|
405
|
+
const diffs = [];
|
|
406
|
+
// update the values
|
|
407
|
+
if (add) {
|
|
408
|
+
for (const role of add) {
|
|
409
|
+
if (original.includes(role))
|
|
410
|
+
continue;
|
|
411
|
+
original.push(role);
|
|
412
|
+
diffs.push(styleText('green', '+' + role));
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
if (remove)
|
|
416
|
+
original = original.filter(item => {
|
|
417
|
+
const allow = !remove.includes(item);
|
|
418
|
+
if (!allow)
|
|
419
|
+
diffs.push(styleText('red', '-' + item));
|
|
420
|
+
return allow;
|
|
421
|
+
});
|
|
422
|
+
return [!!diffs.length, original, diffs.join(', ')];
|
|
423
|
+
}
|
|
424
|
+
program
|
|
425
|
+
.command('user')
|
|
426
|
+
.description('Get or change information about a user')
|
|
427
|
+
.addArgument(lookup)
|
|
428
|
+
.option('-S, --sessions', 'show user sessions')
|
|
429
|
+
.option('-P, --passkeys', 'show user passkeys')
|
|
430
|
+
.option('--add-role <role...>', 'add roles to the user')
|
|
431
|
+
.option('--remove-role <role...>', 'remove roles from the user')
|
|
432
|
+
.option('--tag <tag...>', 'Add tags to the user')
|
|
433
|
+
.option('--untag <tag...>', 'Remove tags from the user')
|
|
434
|
+
.option('--delete', 'Delete the user')
|
|
435
|
+
.action(async (_user, opt) => {
|
|
436
|
+
const env_6 = { stack: [], error: void 0, hasError: false };
|
|
437
|
+
try {
|
|
438
|
+
let user = await _user;
|
|
439
|
+
const _ = __addDisposableResource(env_6, db.connect(), true);
|
|
440
|
+
const [updatedRoles, roles, rolesDiff] = diffUpdate(user.roles, opt.addRole, opt.removeRole);
|
|
441
|
+
const [updatedTags, tags, tagsDiff] = diffUpdate(user.tags, opt.tag, opt.untag);
|
|
442
|
+
if (updatedRoles || updatedTags) {
|
|
443
|
+
user = await db.database
|
|
444
|
+
.updateTable('users')
|
|
445
|
+
.set({ roles, tags })
|
|
446
|
+
.returningAll()
|
|
447
|
+
.executeTakeFirstOrThrow()
|
|
448
|
+
.then(u => {
|
|
449
|
+
if (updatedRoles && rolesDiff)
|
|
450
|
+
console.log(`> Updated roles: ${rolesDiff}`);
|
|
451
|
+
if (updatedTags && tagsDiff)
|
|
452
|
+
console.log(`> Updated tags: ${tagsDiff}`);
|
|
453
|
+
return u;
|
|
454
|
+
})
|
|
455
|
+
.catch(e => exit('Failed to update user roles: ' + e.message));
|
|
456
|
+
}
|
|
457
|
+
if (opt.delete) {
|
|
458
|
+
const env_7 = { stack: [], error: void 0, hasError: false };
|
|
459
|
+
try {
|
|
460
|
+
const rl = __addDisposableResource(env_7, readline(), false);
|
|
461
|
+
const confirmed = await rl
|
|
462
|
+
.question(`Are you sure you want to delete ${userText(user, true)}? (y/N) `)
|
|
463
|
+
.then(v => z.stringbool().parseAsync(v))
|
|
464
|
+
.catch(() => false);
|
|
465
|
+
if (!confirmed)
|
|
466
|
+
console.log(styleText('dim', '> Delete aborted.'));
|
|
467
|
+
else
|
|
468
|
+
await db.database
|
|
469
|
+
.deleteFrom('users')
|
|
470
|
+
.where('id', '=', user.id)
|
|
471
|
+
.executeTakeFirstOrThrow()
|
|
472
|
+
.then(() => console.log(styleText(['red', 'bold'], '> Deleted')))
|
|
473
|
+
.catch(e => exit('Failed to delete user: ' + e.message));
|
|
474
|
+
}
|
|
475
|
+
catch (e_6) {
|
|
476
|
+
env_7.error = e_6;
|
|
477
|
+
env_7.hasError = true;
|
|
478
|
+
}
|
|
479
|
+
finally {
|
|
480
|
+
__disposeResources(env_7);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
console.log([
|
|
484
|
+
user.isAdmin && styleText('redBright', 'Administrator'),
|
|
485
|
+
'UUID: ' + user.id,
|
|
486
|
+
'Name: ' + user.name,
|
|
487
|
+
`Email: ${user.email}, ${user.emailVerified ? 'verified on ' + formatDateRange(user.emailVerified) : styleText(config.auth.email_verification ? 'yellow' : 'dim', 'not verified')}`,
|
|
488
|
+
'Registered ' + formatDateRange(user.registeredAt),
|
|
489
|
+
`Roles: ${user.roles.length ? user.roles.join(', ') : styleText('dim', '(none)')}`,
|
|
490
|
+
`Tags: ${user.tags.length ? user.tags.join(', ') : styleText('dim', '(none)')}`,
|
|
491
|
+
]
|
|
492
|
+
.filter(Boolean)
|
|
493
|
+
.join('\n'));
|
|
494
|
+
if (opt.sessions) {
|
|
495
|
+
const sessions = await db.database.selectFrom('sessions').where('userId', '=', user.id).selectAll().execute();
|
|
496
|
+
console.log(styleText('bold', 'Sessions:'));
|
|
497
|
+
if (!sessions.length)
|
|
498
|
+
console.log(styleText('dim', '(none)'));
|
|
499
|
+
else
|
|
500
|
+
for (const session of sessions) {
|
|
501
|
+
console.log(`\t${session.id}\tcreated ${formatDateRange(session.created).padEnd(40)}\texpires ${formatDateRange(session.expires).padEnd(40)}\t${session.elevated ? styleText('yellow', '(elevated)') : ''}`);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
if (opt.passkeys) {
|
|
505
|
+
const passkeys = await db.database.selectFrom('passkeys').where('userId', '=', user.id).selectAll().execute();
|
|
506
|
+
console.log(styleText('bold', 'Passkeys:'));
|
|
507
|
+
for (const passkey of passkeys) {
|
|
508
|
+
console.log(`\t${passkey.id}: created ${formatDateRange(passkey.createdAt).padEnd(40)} used ${passkey.counter} times. ${passkey.deviceType}, ${passkey.backedUp ? '' : 'not '}backed up; transports are [${passkey.transports.join(', ')}], ${passkey.name ? 'named ' + JSON.stringify(passkey.name) : 'unnamed'}.`);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
catch (e_7) {
|
|
513
|
+
env_6.error = e_7;
|
|
514
|
+
env_6.hasError = true;
|
|
515
|
+
}
|
|
516
|
+
finally {
|
|
517
|
+
const result_6 = __disposeResources(env_6);
|
|
518
|
+
if (result_6)
|
|
519
|
+
await result_6;
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
program
|
|
523
|
+
.command('toggle-admin')
|
|
524
|
+
.description('Toggle whether a user is an administrator')
|
|
525
|
+
.addArgument(lookup)
|
|
526
|
+
.action(async (_user) => {
|
|
527
|
+
const env_8 = { stack: [], error: void 0, hasError: false };
|
|
528
|
+
try {
|
|
529
|
+
const user = await _user;
|
|
530
|
+
const _ = __addDisposableResource(env_8, db.connect(), true);
|
|
531
|
+
const isAdmin = !user.isAdmin;
|
|
532
|
+
await db.database.updateTable('users').set({ isAdmin }).where('id', '=', user.id).executeTakeFirstOrThrow();
|
|
533
|
+
console.log(`${userText(user)} is ${isAdmin ? 'now' : 'no longer'} an administrator. (${styleText(['whiteBright', 'bold'], isAdmin.toString())})`);
|
|
534
|
+
}
|
|
535
|
+
catch (e_8) {
|
|
536
|
+
env_8.error = e_8;
|
|
537
|
+
env_8.hasError = true;
|
|
538
|
+
}
|
|
539
|
+
finally {
|
|
540
|
+
const result_7 = __disposeResources(env_8);
|
|
541
|
+
if (result_7)
|
|
542
|
+
await result_7;
|
|
543
|
+
}
|
|
544
|
+
});
|
|
341
545
|
program
|
|
342
546
|
.command('status')
|
|
343
547
|
.alias('stats')
|
|
344
548
|
.description('Get information about the server')
|
|
345
549
|
.addOption(opts.host)
|
|
346
550
|
.action(async () => {
|
|
347
|
-
const
|
|
551
|
+
const env_9 = { stack: [], error: void 0, hasError: false };
|
|
348
552
|
try {
|
|
349
553
|
console.log('Axium Server v' + program.version());
|
|
350
554
|
console.log(styleText('whiteBright', 'Debug mode:'), config.debug ? styleText('yellow', 'enabled') : 'disabled');
|
|
351
555
|
console.log(styleText('whiteBright', 'Loaded config files:'), config.files.keys().toArray().join(', '));
|
|
352
556
|
process.stdout.write(styleText('whiteBright', 'Database: '));
|
|
353
|
-
const _ = __addDisposableResource(
|
|
557
|
+
const _ = __addDisposableResource(env_9, db.connect(), true);
|
|
354
558
|
try {
|
|
355
559
|
console.log(await db.statusText());
|
|
356
560
|
}
|
|
@@ -367,14 +571,14 @@ program
|
|
|
367
571
|
console.log(await plugin.statusText());
|
|
368
572
|
}
|
|
369
573
|
}
|
|
370
|
-
catch (
|
|
371
|
-
|
|
372
|
-
|
|
574
|
+
catch (e_9) {
|
|
575
|
+
env_9.error = e_9;
|
|
576
|
+
env_9.hasError = true;
|
|
373
577
|
}
|
|
374
578
|
finally {
|
|
375
|
-
const
|
|
376
|
-
if (
|
|
377
|
-
await
|
|
579
|
+
const result_8 = __disposeResources(env_9);
|
|
580
|
+
if (result_8)
|
|
581
|
+
await result_8;
|
|
378
582
|
}
|
|
379
583
|
});
|
|
380
584
|
program
|
|
@@ -411,4 +615,18 @@ program
|
|
|
411
615
|
console.log('Server is listening on port ' + port);
|
|
412
616
|
});
|
|
413
617
|
});
|
|
618
|
+
program.command('link').description('Link svelte page routes').action(linkRoutes);
|
|
619
|
+
program.command('unlink').description('Unlink svelte page routes').action(unlinkRoutes);
|
|
620
|
+
program
|
|
621
|
+
.command('list-links')
|
|
622
|
+
.description('List linked routes')
|
|
623
|
+
.action(async () => {
|
|
624
|
+
for (const link of listRouteLinks()) {
|
|
625
|
+
const idText = link.id.startsWith('#') ? `(${link.id.slice(1)})` : link.id;
|
|
626
|
+
const toColor = await access(link.to)
|
|
627
|
+
.then(() => 'white')
|
|
628
|
+
.catch(() => 'redBright');
|
|
629
|
+
console.log(`${idText}:\t ${styleText('cyanBright', link.from)}\t->\t${styleText(toColor, link.to)}`);
|
|
630
|
+
}
|
|
631
|
+
});
|
|
414
632
|
program.parse();
|
package/dist/config.d.ts
CHANGED
|
@@ -34,12 +34,15 @@ export interface Config extends Record<string, unknown> {
|
|
|
34
34
|
console: boolean;
|
|
35
35
|
};
|
|
36
36
|
web: {
|
|
37
|
-
prefix: string;
|
|
38
37
|
assets: string;
|
|
39
|
-
|
|
38
|
+
disable_cache: boolean;
|
|
40
39
|
port: number;
|
|
40
|
+
prefix: string;
|
|
41
|
+
routes: string;
|
|
42
|
+
secure: boolean;
|
|
41
43
|
ssl_key: string;
|
|
42
44
|
ssl_cert: string;
|
|
45
|
+
template: string;
|
|
43
46
|
};
|
|
44
47
|
}
|
|
45
48
|
export declare const configFiles: Map<string, File>;
|
|
@@ -92,12 +95,15 @@ export declare const File: z.ZodObject<{
|
|
|
92
95
|
console: z.ZodOptional<z.ZodBoolean>;
|
|
93
96
|
}, z.core.$strip>>;
|
|
94
97
|
web: z.ZodOptional<z.ZodObject<{
|
|
95
|
-
prefix: z.ZodOptional<z.ZodString>;
|
|
96
98
|
assets: z.ZodOptional<z.ZodString>;
|
|
97
|
-
|
|
99
|
+
disable_cache: z.ZodOptional<z.ZodBoolean>;
|
|
98
100
|
port: z.ZodOptional<z.ZodNumber>;
|
|
101
|
+
prefix: z.ZodOptional<z.ZodString>;
|
|
102
|
+
routes: z.ZodOptional<z.ZodString>;
|
|
103
|
+
secure: z.ZodOptional<z.ZodBoolean>;
|
|
99
104
|
ssl_key: z.ZodOptional<z.ZodString>;
|
|
100
105
|
ssl_cert: z.ZodOptional<z.ZodString>;
|
|
106
|
+
template: z.ZodOptional<z.ZodString>;
|
|
101
107
|
}, z.core.$strip>>;
|
|
102
108
|
include: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodString>>>;
|
|
103
109
|
plugins: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodString>>>;
|
package/dist/config.js
CHANGED
|
@@ -51,12 +51,15 @@ export const config = _unique('config', {
|
|
|
51
51
|
level: 'info',
|
|
52
52
|
},
|
|
53
53
|
web: {
|
|
54
|
-
prefix: '',
|
|
55
54
|
assets: '',
|
|
56
|
-
|
|
55
|
+
disable_cache: false,
|
|
57
56
|
port: 443,
|
|
57
|
+
prefix: '',
|
|
58
|
+
routes: 'routes',
|
|
59
|
+
secure: true,
|
|
58
60
|
ssl_key: resolve(dirs[0], 'ssl_key.pem'),
|
|
59
61
|
ssl_cert: resolve(dirs[0], 'ssl_cert.pem'),
|
|
62
|
+
template: join(import.meta.dirname, '../web/template.html'),
|
|
60
63
|
},
|
|
61
64
|
});
|
|
62
65
|
export default config;
|
|
@@ -106,12 +109,15 @@ export const File = z
|
|
|
106
109
|
.partial(),
|
|
107
110
|
web: z
|
|
108
111
|
.object({
|
|
109
|
-
prefix: z.string(),
|
|
110
112
|
assets: z.string(),
|
|
111
|
-
|
|
113
|
+
disable_cache: z.boolean(),
|
|
112
114
|
port: z.number().min(1).max(65535),
|
|
115
|
+
prefix: z.string(),
|
|
116
|
+
routes: z.string(),
|
|
117
|
+
secure: z.boolean(),
|
|
113
118
|
ssl_key: z.string(),
|
|
114
119
|
ssl_cert: z.string(),
|
|
120
|
+
template: z.string(),
|
|
115
121
|
})
|
|
116
122
|
.partial(),
|
|
117
123
|
include: z.array(z.string()).optional(),
|
|
@@ -152,7 +158,7 @@ export async function loadConfig(path, options = {}) {
|
|
|
152
158
|
catch (e) {
|
|
153
159
|
if (!options.optional)
|
|
154
160
|
throw e;
|
|
155
|
-
|
|
161
|
+
output.debug(`Skipping config at ${path} (${e.message})`);
|
|
156
162
|
return;
|
|
157
163
|
}
|
|
158
164
|
const file = options.strict ? File.parse(json) : json;
|
|
@@ -184,7 +190,7 @@ export function saveConfigTo(path, changed) {
|
|
|
184
190
|
setConfig(changed);
|
|
185
191
|
const config = configFiles.get(path) ?? {};
|
|
186
192
|
Object.assign(config, { ...changed, db: { ...config.db, ...changed.db } });
|
|
187
|
-
|
|
193
|
+
output.debug(`Wrote config to ${path}`);
|
|
188
194
|
writeFileSync(path, JSON.stringify(config));
|
|
189
195
|
}
|
|
190
196
|
/**
|
package/dist/database.d.ts
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import type { Preferences } from '@axium/core';
|
|
2
|
+
import type { AuthenticatorTransportFuture, CredentialDeviceType } from '@simplewebauthn/server';
|
|
2
3
|
import { Kysely, type GeneratedAlways } from 'kysely';
|
|
3
4
|
import type { VerificationRole } from './auth.js';
|
|
4
|
-
import type { MaybeOutput, WithOutput } from './io.js';
|
|
5
|
-
import type { AuthenticatorTransportFuture, CredentialDeviceType } from '@simplewebauthn/server';
|
|
6
5
|
export interface Schema {
|
|
7
6
|
users: {
|
|
8
|
-
id:
|
|
7
|
+
id: string;
|
|
9
8
|
email: string;
|
|
10
9
|
name: string;
|
|
11
10
|
image?: string | null;
|
|
12
11
|
emailVerified?: Date | null;
|
|
13
|
-
preferences
|
|
12
|
+
preferences: Preferences;
|
|
13
|
+
isAdmin: boolean;
|
|
14
|
+
roles: string[];
|
|
15
|
+
tags: string[];
|
|
16
|
+
registeredAt: GeneratedAlways<Date>;
|
|
14
17
|
};
|
|
15
18
|
sessions: {
|
|
16
19
|
id: GeneratedAlways<string>;
|
|
@@ -49,19 +52,16 @@ export interface Stats {
|
|
|
49
52
|
export declare function count<const T extends keyof Schema>(table: T): Promise<number>;
|
|
50
53
|
export declare function status(): Promise<Stats>;
|
|
51
54
|
export declare function statusText(): Promise<string>;
|
|
52
|
-
export interface OpOptions
|
|
53
|
-
timeout: number;
|
|
55
|
+
export interface OpOptions {
|
|
54
56
|
force: boolean;
|
|
55
57
|
}
|
|
56
58
|
export interface InitOptions extends OpOptions {
|
|
57
59
|
skip: boolean;
|
|
58
60
|
}
|
|
59
|
-
export declare function shouldRecreate(opt: InitOptions
|
|
60
|
-
export declare function getHBA(opt: OpOptions
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
warnExists: (error: string | Error) => void;
|
|
64
|
-
}
|
|
61
|
+
export declare function shouldRecreate(opt: InitOptions): boolean;
|
|
62
|
+
export declare function getHBA(opt: OpOptions): Promise<[content: string, writeBack: (newContent: string) => void]>;
|
|
63
|
+
/** Shortcut to output a warning if an error is thrown because relation already exists */
|
|
64
|
+
export declare const warnExists: (error: string | Error) => void;
|
|
65
65
|
export declare function init(opt: InitOptions): Promise<void>;
|
|
66
66
|
export declare function check(opt: OpOptions): Promise<void>;
|
|
67
67
|
export declare function clean(opt: Partial<OpOptions>): Promise<void>;
|