@axium/server 0.26.3 → 0.28.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/acl.d.ts +26 -45
- package/dist/acl.js +50 -52
- package/dist/api/acl.js +16 -8
- package/dist/api/admin.js +9 -12
- package/dist/api/metadata.js +4 -11
- package/dist/api/passkeys.js +6 -6
- package/dist/api/register.js +1 -1
- package/dist/api/users.js +16 -30
- package/dist/audit.d.ts +3 -3
- package/dist/audit.js +8 -9
- package/dist/auth.d.ts +10 -5
- package/dist/auth.js +29 -23
- package/dist/cli.d.ts +8 -2
- package/dist/cli.js +18 -605
- package/dist/config.d.ts +2 -2
- package/dist/config.js +8 -7
- package/dist/database.d.ts +417 -29
- package/dist/database.js +546 -247
- package/dist/db.json +71 -0
- package/dist/internal_requests.js +1 -1
- package/dist/main.d.ts +2 -0
- package/dist/main.js +833 -0
- package/dist/requests.d.ts +1 -1
- package/dist/requests.js +8 -1
- package/dist/routes.d.ts +20 -20
- package/dist/routes.js +2 -1
- package/dist/serve.js +1 -1
- package/package.json +6 -4
- package/routes/account/+page.svelte +11 -13
- package/routes/admin/audit/[id]/+page.svelte +6 -1
- package/routes/admin/plugins/+page.svelte +5 -1
- package/schemas/config.json +207 -0
- package/schemas/db.json +636 -0
- package/svelte.config.js +3 -0
package/dist/requests.d.ts
CHANGED
package/dist/requests.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import {} from '@axium/core';
|
|
2
|
+
import * as io from '@axium/core/io';
|
|
1
3
|
import { userProtectedFields, userPublicFields } from '@axium/core/user';
|
|
2
4
|
import * as cookie from 'cookie_v1';
|
|
3
5
|
import { pick } from 'utilium';
|
|
4
6
|
import * as z from 'zod';
|
|
7
|
+
import { audit } from './audit.js';
|
|
5
8
|
import { createSession } from './auth.js';
|
|
6
9
|
import { config } from './config.js';
|
|
7
10
|
export function isResponseError(e) {
|
|
@@ -25,7 +28,7 @@ export function redirect(location, status = 302) {
|
|
|
25
28
|
export function json(data, init) {
|
|
26
29
|
const response = Response.json(data, init);
|
|
27
30
|
if (!response.headers.has('content-length')) {
|
|
28
|
-
response.headers.set('content-length', JSON.stringify(data).length.toString());
|
|
31
|
+
response.headers.set('content-length', new TextEncoder().encode(JSON.stringify(data)).length.toString());
|
|
29
32
|
}
|
|
30
33
|
return response;
|
|
31
34
|
}
|
|
@@ -71,6 +74,10 @@ export function withError(text, code = 500) {
|
|
|
71
74
|
return function (e) {
|
|
72
75
|
if (e.name == 'ResponseError')
|
|
73
76
|
throw e;
|
|
77
|
+
if (code == 500) {
|
|
78
|
+
void audit('response_error', undefined, { stack: e.stack });
|
|
79
|
+
io.error('(in response) ' + e.stack);
|
|
80
|
+
}
|
|
74
81
|
error(code, text + (config.debug && e.message ? `: ${e.message}` : ''));
|
|
75
82
|
};
|
|
76
83
|
}
|
package/dist/routes.d.ts
CHANGED
|
@@ -1,53 +1,53 @@
|
|
|
1
1
|
import type { RequestMethod } from '@axium/core/requests';
|
|
2
2
|
import type { Component } from 'svelte';
|
|
3
3
|
import type z from 'zod';
|
|
4
|
-
type
|
|
4
|
+
type RouteParams = Record<string, z.ZodType>;
|
|
5
|
+
type ParamValues<P extends RouteParams> = {
|
|
6
|
+
[K in keyof P]: z.infer<P[K]>;
|
|
7
|
+
};
|
|
5
8
|
export type MaybePromise<T> = T | Promise<T>;
|
|
6
|
-
export type EndpointHandlers<Params
|
|
7
|
-
export type RouteParamOptions = z.ZodType;
|
|
8
|
-
export interface CommonRouteOptions<Params extends _Params = _Params> {
|
|
9
|
-
path: string;
|
|
10
|
-
params?: {
|
|
11
|
-
[K in keyof Params]?: RouteParamOptions;
|
|
12
|
-
};
|
|
13
|
-
}
|
|
9
|
+
export type EndpointHandlers<Params, This = unknown> = Partial<Record<RequestMethod, (this: This, request: Request, params: Params) => MaybePromise<object | Response>>>;
|
|
14
10
|
/**
|
|
15
11
|
* A route with server-side handlers for different HTTP methods.
|
|
16
12
|
*/
|
|
17
|
-
export interface
|
|
13
|
+
export interface ServerRouteInit<Params extends RouteParams = RouteParams> extends EndpointHandlers<ParamValues<Params>, RouteCommon<Params>> {
|
|
14
|
+
path: string;
|
|
15
|
+
params?: Params;
|
|
18
16
|
api?: boolean;
|
|
19
17
|
}
|
|
20
|
-
export interface
|
|
18
|
+
export interface WebRouteInit<Params extends RouteParams = RouteParams> {
|
|
19
|
+
path: string;
|
|
20
|
+
params?: Params;
|
|
21
21
|
load?(request: Request): object | Promise<object>;
|
|
22
22
|
/** the Svelte page */
|
|
23
23
|
page?: Component;
|
|
24
24
|
}
|
|
25
|
-
export type
|
|
26
|
-
export interface RouteCommon {
|
|
25
|
+
export type RouteInit<Params extends RouteParams = RouteParams> = ServerRouteInit<Params> | WebRouteInit<Params>;
|
|
26
|
+
export interface RouteCommon<Params extends RouteParams = RouteParams> {
|
|
27
27
|
path: string;
|
|
28
|
-
params?:
|
|
28
|
+
params?: Params;
|
|
29
29
|
}
|
|
30
|
-
export interface ServerRoute extends RouteCommon
|
|
30
|
+
export interface ServerRoute<Params extends RouteParams = RouteParams> extends RouteCommon<Params>, EndpointHandlers<ParamValues<Params>> {
|
|
31
31
|
api: boolean;
|
|
32
32
|
server: true;
|
|
33
33
|
}
|
|
34
|
-
export interface WebRoute extends RouteCommon {
|
|
34
|
+
export interface WebRoute<Params extends RouteParams = RouteParams> extends RouteCommon<Params> {
|
|
35
35
|
server: false;
|
|
36
36
|
load?(request: Request): object | Promise<object>;
|
|
37
37
|
page: Component;
|
|
38
38
|
}
|
|
39
|
-
export type Route = ServerRoute | WebRoute
|
|
39
|
+
export type Route<Params extends RouteParams = RouteParams> = ServerRoute<Params> | WebRoute<Params>;
|
|
40
40
|
/**
|
|
41
41
|
* @internal
|
|
42
42
|
*/
|
|
43
|
-
export declare const routes: Map<string, Route
|
|
43
|
+
export declare const routes: Map<string, Route<any>>;
|
|
44
44
|
/**
|
|
45
45
|
* @category Plugin API
|
|
46
46
|
*/
|
|
47
|
-
export declare function addRoute(opt:
|
|
47
|
+
export declare function addRoute<const P extends RouteParams = RouteParams>(opt: RouteInit<P>): void;
|
|
48
48
|
/**
|
|
49
49
|
* Resolve a request URL into a route.
|
|
50
50
|
* This handles parsing of parameters in the URL.
|
|
51
51
|
*/
|
|
52
|
-
export declare function resolveRoute(url: URL): [Route
|
|
52
|
+
export declare function resolveRoute<P extends RouteParams = RouteParams>(url: URL): [Route<P>, params: ParamValues<P>] | void;
|
|
53
53
|
export {};
|
package/dist/routes.js
CHANGED
|
@@ -27,8 +27,9 @@ export function addRoute(opt) {
|
|
|
27
27
|
*/
|
|
28
28
|
export function resolveRoute(url) {
|
|
29
29
|
const { pathname } = url;
|
|
30
|
-
if (routes.has(pathname) && !pathname.split('/').some(p => p.startsWith(':')))
|
|
30
|
+
if (routes.has(pathname) && !pathname.split('/').some(p => p.startsWith(':'))) {
|
|
31
31
|
return [routes.get(pathname), {}];
|
|
32
|
+
}
|
|
32
33
|
// Otherwise we must have a parameterized route
|
|
33
34
|
_routes: for (const route of routes.values()) {
|
|
34
35
|
const params = {};
|
package/dist/serve.js
CHANGED
|
@@ -131,7 +131,7 @@ async function _runRoute(run, request, params) {
|
|
|
131
131
|
async function _getLinkedBuildHandler(buildPath = '../build/handler.js') {
|
|
132
132
|
const { handler: handleFrontendRequest } = await import(buildPath);
|
|
133
133
|
return function handle(req, res) {
|
|
134
|
-
const url = new URL(req.url, config.
|
|
134
|
+
const url = new URL(req.url, config.origin);
|
|
135
135
|
const [route, params = {}] = resolveRoute(url) ?? [];
|
|
136
136
|
if (!route && url.pathname === '/' && config.debug_home) {
|
|
137
137
|
res.writeHead(303, { Location: '/_axium/default' }).end();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axium/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"author": "James Prevett <axium@jamespre.dev>",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "individual",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"assets",
|
|
32
32
|
"dist",
|
|
33
33
|
"routes",
|
|
34
|
+
"schemas",
|
|
34
35
|
"svelte.config.js",
|
|
35
36
|
"web.tsconfig.json",
|
|
36
37
|
"template.html",
|
|
@@ -38,15 +39,16 @@
|
|
|
38
39
|
"axium.service"
|
|
39
40
|
],
|
|
40
41
|
"bin": {
|
|
41
|
-
"axium": "dist/
|
|
42
|
+
"axium": "dist/main.js"
|
|
42
43
|
},
|
|
43
44
|
"scripts": {
|
|
44
45
|
"build": "tsc",
|
|
46
|
+
"build:schemas": "mkdir -p schemas && npx axium config schema -j > schemas/config.json && npx axium db schema -j > schemas/db.json",
|
|
45
47
|
"clean": "rm -rf build .svelte-kit node_modules/{.vite,.vite-temp}"
|
|
46
48
|
},
|
|
47
49
|
"peerDependencies": {
|
|
48
|
-
"@axium/client": ">=0.
|
|
49
|
-
"@axium/core": ">=0.
|
|
50
|
+
"@axium/client": ">=0.9.0",
|
|
51
|
+
"@axium/core": ">=0.12.0",
|
|
50
52
|
"kysely": "^0.28.0",
|
|
51
53
|
"utilium": "^2.3.8",
|
|
52
54
|
"zod": "^4.0.5"
|
|
@@ -8,8 +8,6 @@
|
|
|
8
8
|
const { data }: PageProps = $props();
|
|
9
9
|
const { canVerify } = data;
|
|
10
10
|
|
|
11
|
-
const dialogs = $state<Record<string, HTMLDialogElement>>({});
|
|
12
|
-
|
|
13
11
|
let verificationSent = $state(false);
|
|
14
12
|
let currentSession = $state(data.currentSession);
|
|
15
13
|
let user = $state(data.user);
|
|
@@ -27,7 +25,7 @@
|
|
|
27
25
|
</svelte:head>
|
|
28
26
|
|
|
29
27
|
{#snippet action(name: string, i: string = 'pen')}
|
|
30
|
-
<button style:display="contents"
|
|
28
|
+
<button style:display="contents" commandfor={name} command="show-modal">
|
|
31
29
|
<Icon {i} --size="16px" />
|
|
32
30
|
</button>
|
|
33
31
|
{/snippet}
|
|
@@ -45,7 +43,7 @@
|
|
|
45
43
|
<p>{user.name}</p>
|
|
46
44
|
{@render action('edit_name')}
|
|
47
45
|
</div>
|
|
48
|
-
<FormDialog
|
|
46
|
+
<FormDialog id="edit_name" submit={_editUser} submitText="Change">
|
|
49
47
|
<div>
|
|
50
48
|
<label for="name">What do you want to be called?</label>
|
|
51
49
|
<input name="name" type="text" value={user.name || ''} required />
|
|
@@ -67,7 +65,7 @@
|
|
|
67
65
|
</p>
|
|
68
66
|
{@render action('edit_email')}
|
|
69
67
|
</div>
|
|
70
|
-
<FormDialog
|
|
68
|
+
<FormDialog id="edit_email" submit={_editUser} submitText="Change">
|
|
71
69
|
<div>
|
|
72
70
|
<label for="email">Email Address</label>
|
|
73
71
|
<input name="email" type="email" value={user.email || ''} required />
|
|
@@ -80,11 +78,11 @@
|
|
|
80
78
|
<ClipboardCopy value={user.id} --size="16px" />
|
|
81
79
|
</div>
|
|
82
80
|
<span>
|
|
83
|
-
<button class="signout"
|
|
84
|
-
<button style:cursor="pointer"
|
|
85
|
-
<Logout
|
|
81
|
+
<button class="signout" command="show-modal" commandfor="logout">Sign Out</button>
|
|
82
|
+
<button style:cursor="pointer" command="show-modal" commandfor="delete" class="danger">Delete Account</button>
|
|
83
|
+
<Logout />
|
|
86
84
|
<FormDialog
|
|
87
|
-
|
|
85
|
+
id="delete"
|
|
88
86
|
submit={() => deleteUser(user.id).then(() => (window.location.href = '/'))}
|
|
89
87
|
submitText="Delete Account"
|
|
90
88
|
submitDanger
|
|
@@ -110,9 +108,9 @@
|
|
|
110
108
|
<p class="subtle"><i>Unnamed</i></p>
|
|
111
109
|
{/if}
|
|
112
110
|
<p>Created {passkey.createdAt.toLocaleString()}</p>
|
|
113
|
-
{@render action('edit_passkey
|
|
111
|
+
{@render action('edit_passkey:' + passkey.id)}
|
|
114
112
|
{#if passkeys.length > 1}
|
|
115
|
-
{@render action('delete_passkey
|
|
113
|
+
{@render action('delete_passkey:' + passkey.id, 'trash')}
|
|
116
114
|
{:else}
|
|
117
115
|
<dfn title="You must have at least one passkey" class="disabled">
|
|
118
116
|
<Icon i="trash-slash" --fill="#888" --size="16px" />
|
|
@@ -120,7 +118,7 @@
|
|
|
120
118
|
{/if}
|
|
121
119
|
</div>
|
|
122
120
|
<FormDialog
|
|
123
|
-
|
|
121
|
+
id={'edit_passkey:' + passkey.id}
|
|
124
122
|
submit={data => {
|
|
125
123
|
if (typeof data.name != 'string') throw 'Passkey name must be a string';
|
|
126
124
|
passkey.name = data.name;
|
|
@@ -134,7 +132,7 @@
|
|
|
134
132
|
</div>
|
|
135
133
|
</FormDialog>
|
|
136
134
|
<FormDialog
|
|
137
|
-
|
|
135
|
+
id={'delete_passkey:' + passkey.id}
|
|
138
136
|
submit={() => deletePasskey(passkey.id).then(() => passkeys.splice(passkeys.indexOf(passkey), 1))}
|
|
139
137
|
submitText="Delete"
|
|
140
138
|
submitDanger={true}
|
|
@@ -15,7 +15,11 @@
|
|
|
15
15
|
<p><strong>Author:</strong> {plugin.author}</p>
|
|
16
16
|
<p>
|
|
17
17
|
<strong>Provided apps:</strong>
|
|
18
|
-
{#if plugin.apps?.length}
|
|
18
|
+
{#if plugin.apps?.length}
|
|
19
|
+
{#each plugin.apps as app, i}
|
|
20
|
+
<a href="/{app.id}">{app.name}</a>{i != plugin.apps.length - 1 ? ', ' : ''}
|
|
21
|
+
{/each}
|
|
22
|
+
{:else}<i>None</i>{/if}
|
|
19
23
|
</p>
|
|
20
24
|
<p>{plugin.description}</p>
|
|
21
25
|
{:else}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"admin_api": {
|
|
6
|
+
"type": "boolean"
|
|
7
|
+
},
|
|
8
|
+
"allow_new_users": {
|
|
9
|
+
"type": "boolean"
|
|
10
|
+
},
|
|
11
|
+
"apps": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"properties": {
|
|
14
|
+
"disabled": {
|
|
15
|
+
"type": "array",
|
|
16
|
+
"items": {
|
|
17
|
+
"type": "string"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"additionalProperties": {}
|
|
22
|
+
},
|
|
23
|
+
"audit": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"properties": {
|
|
26
|
+
"allow_raw": {
|
|
27
|
+
"type": "boolean"
|
|
28
|
+
},
|
|
29
|
+
"retention": {
|
|
30
|
+
"type": "number",
|
|
31
|
+
"minimum": 0
|
|
32
|
+
},
|
|
33
|
+
"min_severity": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"enum": [
|
|
36
|
+
"emergency",
|
|
37
|
+
"alert",
|
|
38
|
+
"critical",
|
|
39
|
+
"error",
|
|
40
|
+
"warning",
|
|
41
|
+
"notice",
|
|
42
|
+
"info",
|
|
43
|
+
"debug",
|
|
44
|
+
"Emergency",
|
|
45
|
+
"Alert",
|
|
46
|
+
"Critical",
|
|
47
|
+
"Error",
|
|
48
|
+
"Warning",
|
|
49
|
+
"Notice",
|
|
50
|
+
"Info",
|
|
51
|
+
"Debug"
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
"auto_suspend": {
|
|
55
|
+
"type": "string",
|
|
56
|
+
"enum": [
|
|
57
|
+
"emergency",
|
|
58
|
+
"alert",
|
|
59
|
+
"critical",
|
|
60
|
+
"error",
|
|
61
|
+
"warning",
|
|
62
|
+
"notice",
|
|
63
|
+
"info",
|
|
64
|
+
"debug",
|
|
65
|
+
"Emergency",
|
|
66
|
+
"Alert",
|
|
67
|
+
"Critical",
|
|
68
|
+
"Error",
|
|
69
|
+
"Warning",
|
|
70
|
+
"Notice",
|
|
71
|
+
"Info",
|
|
72
|
+
"Debug"
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"additionalProperties": {}
|
|
77
|
+
},
|
|
78
|
+
"auth": {
|
|
79
|
+
"type": "object",
|
|
80
|
+
"properties": {
|
|
81
|
+
"passkey_probation": {
|
|
82
|
+
"type": "number"
|
|
83
|
+
},
|
|
84
|
+
"rp_id": {
|
|
85
|
+
"type": "string"
|
|
86
|
+
},
|
|
87
|
+
"rp_name": {
|
|
88
|
+
"type": "string"
|
|
89
|
+
},
|
|
90
|
+
"secure_cookies": {
|
|
91
|
+
"type": "boolean"
|
|
92
|
+
},
|
|
93
|
+
"verification_timeout": {
|
|
94
|
+
"type": "number"
|
|
95
|
+
},
|
|
96
|
+
"email_verification": {
|
|
97
|
+
"type": "boolean"
|
|
98
|
+
},
|
|
99
|
+
"header_only": {
|
|
100
|
+
"type": "boolean"
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"additionalProperties": {}
|
|
104
|
+
},
|
|
105
|
+
"db": {
|
|
106
|
+
"type": "object",
|
|
107
|
+
"properties": {
|
|
108
|
+
"host": {
|
|
109
|
+
"type": "string"
|
|
110
|
+
},
|
|
111
|
+
"port": {
|
|
112
|
+
"type": "number"
|
|
113
|
+
},
|
|
114
|
+
"password": {
|
|
115
|
+
"type": "string"
|
|
116
|
+
},
|
|
117
|
+
"user": {
|
|
118
|
+
"type": "string"
|
|
119
|
+
},
|
|
120
|
+
"database": {
|
|
121
|
+
"type": "string"
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"additionalProperties": {}
|
|
125
|
+
},
|
|
126
|
+
"debug": {
|
|
127
|
+
"type": "boolean"
|
|
128
|
+
},
|
|
129
|
+
"debug_home": {
|
|
130
|
+
"type": "boolean"
|
|
131
|
+
},
|
|
132
|
+
"log": {
|
|
133
|
+
"type": "object",
|
|
134
|
+
"properties": {
|
|
135
|
+
"level": {
|
|
136
|
+
"type": "string",
|
|
137
|
+
"enum": [
|
|
138
|
+
"error",
|
|
139
|
+
"warn",
|
|
140
|
+
"notice",
|
|
141
|
+
"info",
|
|
142
|
+
"debug"
|
|
143
|
+
]
|
|
144
|
+
},
|
|
145
|
+
"console": {
|
|
146
|
+
"type": "boolean"
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
"additionalProperties": {}
|
|
150
|
+
},
|
|
151
|
+
"origin": {
|
|
152
|
+
"type": "string"
|
|
153
|
+
},
|
|
154
|
+
"request_size_limit": {
|
|
155
|
+
"type": "number",
|
|
156
|
+
"minimum": 0
|
|
157
|
+
},
|
|
158
|
+
"show_duplicate_state": {
|
|
159
|
+
"type": "boolean"
|
|
160
|
+
},
|
|
161
|
+
"web": {
|
|
162
|
+
"type": "object",
|
|
163
|
+
"properties": {
|
|
164
|
+
"disable_cache": {
|
|
165
|
+
"type": "boolean"
|
|
166
|
+
},
|
|
167
|
+
"port": {
|
|
168
|
+
"type": "number",
|
|
169
|
+
"minimum": 1,
|
|
170
|
+
"maximum": 65535
|
|
171
|
+
},
|
|
172
|
+
"prefix": {
|
|
173
|
+
"type": "string"
|
|
174
|
+
},
|
|
175
|
+
"routes": {
|
|
176
|
+
"type": "string"
|
|
177
|
+
},
|
|
178
|
+
"secure": {
|
|
179
|
+
"type": "boolean"
|
|
180
|
+
},
|
|
181
|
+
"ssl_key": {
|
|
182
|
+
"type": "string"
|
|
183
|
+
},
|
|
184
|
+
"ssl_cert": {
|
|
185
|
+
"type": "string"
|
|
186
|
+
},
|
|
187
|
+
"build": {
|
|
188
|
+
"type": "string"
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
"additionalProperties": {}
|
|
192
|
+
},
|
|
193
|
+
"include": {
|
|
194
|
+
"type": "array",
|
|
195
|
+
"items": {
|
|
196
|
+
"type": "string"
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
"plugins": {
|
|
200
|
+
"type": "array",
|
|
201
|
+
"items": {
|
|
202
|
+
"type": "string"
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
"additionalProperties": {}
|
|
207
|
+
}
|