@axium/client 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/styles.css +50 -0
- package/dist/cli/config.d.ts +2 -0
- package/dist/config.d.ts +5 -3
- package/dist/requests.d.ts +3 -2
- package/dist/requests.js +19 -1
- package/dist/user.d.ts +5 -1
- package/dist/user.js +19 -54
- package/lib/FormDialog.svelte +2 -3
- package/lib/URLText.svelte +21 -0
- package/lib/index.ts +1 -1
- package/package.json +2 -2
- package/lib/Dialog.svelte +0 -53
package/assets/styles.css
CHANGED
|
@@ -101,6 +101,53 @@ pre {
|
|
|
101
101
|
border-radius: 0.5em;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
dialog {
|
|
105
|
+
border-radius: 1em;
|
|
106
|
+
background: var(--bg-menu);
|
|
107
|
+
border: 1px solid #8888;
|
|
108
|
+
padding: 1em;
|
|
109
|
+
max-width: calc(100% - 2em);
|
|
110
|
+
word-wrap: normal;
|
|
111
|
+
|
|
112
|
+
form {
|
|
113
|
+
max-width: 100%;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
dialog::backdrop {
|
|
118
|
+
background: #0003;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
dialog[open] {
|
|
122
|
+
animation: zoom 0.25s cubic-bezier(0.35, 1.55, 0.65, 1);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@keyframes zoom {
|
|
126
|
+
from {
|
|
127
|
+
transform: scale(0.95);
|
|
128
|
+
}
|
|
129
|
+
to {
|
|
130
|
+
transform: scale(1);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
dialog[open]::backdrop {
|
|
135
|
+
animation: fade 0.25s ease-out;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@keyframes fade {
|
|
139
|
+
from {
|
|
140
|
+
opacity: 0;
|
|
141
|
+
}
|
|
142
|
+
to {
|
|
143
|
+
opacity: 1;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
dialog form {
|
|
148
|
+
display: contents;
|
|
149
|
+
}
|
|
150
|
+
|
|
104
151
|
.error {
|
|
105
152
|
padding: 1em;
|
|
106
153
|
border-radius: 0.5em;
|
|
@@ -208,6 +255,9 @@ h6 {
|
|
|
208
255
|
}
|
|
209
256
|
|
|
210
257
|
@media (width < 700px) {
|
|
258
|
+
dialog {
|
|
259
|
+
}
|
|
260
|
+
|
|
211
261
|
.mobile-hide {
|
|
212
262
|
display: none !important;
|
|
213
263
|
}
|
package/dist/cli/config.d.ts
CHANGED
|
@@ -14,8 +14,10 @@ export declare function session(): {
|
|
|
14
14
|
debug: boolean;
|
|
15
15
|
};
|
|
16
16
|
roles: string[];
|
|
17
|
+
tags: string[];
|
|
17
18
|
registeredAt: Date;
|
|
18
19
|
isAdmin: boolean;
|
|
20
|
+
isSuspended: boolean;
|
|
19
21
|
emailVerified?: Date | null | undefined;
|
|
20
22
|
image?: string | null | undefined;
|
|
21
23
|
};
|
package/dist/config.d.ts
CHANGED
|
@@ -14,14 +14,16 @@ export declare const ClientConfig: z.ZodObject<{
|
|
|
14
14
|
id: z.ZodUUID;
|
|
15
15
|
name: z.ZodString;
|
|
16
16
|
email: z.ZodEmail;
|
|
17
|
-
emailVerified: z.ZodOptional<z.ZodNullable<z.
|
|
17
|
+
emailVerified: z.ZodOptional<z.ZodNullable<z.ZodCoercedDate<unknown>>>;
|
|
18
18
|
image: z.ZodOptional<z.ZodNullable<z.ZodURL>>;
|
|
19
|
-
preferences: z.ZodObject<{
|
|
19
|
+
preferences: z.ZodLazy<z.ZodObject<{
|
|
20
20
|
debug: z.ZodDefault<z.ZodBoolean>;
|
|
21
|
-
}, z.core.$strip
|
|
21
|
+
}, z.core.$strip>>;
|
|
22
22
|
roles: z.ZodArray<z.ZodString>;
|
|
23
|
+
tags: z.ZodArray<z.ZodString>;
|
|
23
24
|
registeredAt: z.ZodCoercedDate<unknown>;
|
|
24
25
|
isAdmin: z.ZodBoolean;
|
|
26
|
+
isSuspended: z.ZodBoolean;
|
|
25
27
|
}, z.core.$strip>;
|
|
26
28
|
}, z.core.$strip>;
|
|
27
29
|
apps: z.ZodArray<z.ZodObject<{
|
package/dist/requests.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { APIParameters, APIValues, Endpoint, RequestBody } from '@axium/core/api';
|
|
2
|
+
import { $API } from '@axium/core/api';
|
|
2
3
|
import type { RequestMethod } from '@axium/core/requests';
|
|
3
4
|
export declare let token: string | null;
|
|
4
5
|
export declare function setToken(value: string | null): void;
|
|
5
6
|
export declare let prefix: string;
|
|
6
7
|
export declare function setPrefix(value: string): void;
|
|
7
|
-
export declare function fetchAPI<const
|
|
8
|
+
export declare function fetchAPI<const E extends Endpoint, const M extends keyof $API[E] & RequestMethod>(method: M, endpoint: E, data?: RequestBody<M, E>, ...params: APIParameters<E>): Promise<M extends keyof APIValues[E] ? (APIValues[E][M] extends readonly [unknown, infer R] ? R : APIValues[E][M]) : unknown>;
|
package/dist/requests.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { $API } from '@axium/core/api';
|
|
2
|
+
import { prettifyError } from 'zod';
|
|
1
3
|
export let token = null;
|
|
2
4
|
export function setToken(value) {
|
|
3
5
|
token = value;
|
|
@@ -14,6 +16,14 @@ export async function fetchAPI(method, endpoint, data, ...params) {
|
|
|
14
16
|
Accept: 'application/json',
|
|
15
17
|
},
|
|
16
18
|
};
|
|
19
|
+
const schema = $API[endpoint]?.[method];
|
|
20
|
+
if (schema && Array.isArray(schema))
|
|
21
|
+
try {
|
|
22
|
+
data = schema[0].parse(data);
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
throw prettifyError(e);
|
|
26
|
+
}
|
|
17
27
|
if (method !== 'GET' && method !== 'HEAD')
|
|
18
28
|
options.body = JSON.stringify(data);
|
|
19
29
|
const search = method != 'GET' || typeof data != 'object' || data == null || !Object.keys(data).length
|
|
@@ -39,5 +49,13 @@ export async function fetchAPI(method, endpoint, data, ...params) {
|
|
|
39
49
|
const json = await response.json().catch(() => ({ message: 'Unknown server error (invalid JSON response)' }));
|
|
40
50
|
if (!response.ok)
|
|
41
51
|
throw new Error(json.message);
|
|
42
|
-
|
|
52
|
+
if (!schema)
|
|
53
|
+
return json;
|
|
54
|
+
const Output = Array.isArray(schema) ? schema[1] : schema;
|
|
55
|
+
try {
|
|
56
|
+
return Output.parse(json);
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
throw prettifyError(e);
|
|
60
|
+
}
|
|
43
61
|
}
|
package/dist/user.d.ts
CHANGED
|
@@ -19,7 +19,11 @@ export declare function updateUser(userId: string, data: Record<string, FormData
|
|
|
19
19
|
export declare function fullUserInfo(userId: string): Promise<User & {
|
|
20
20
|
sessions: Session[];
|
|
21
21
|
}>;
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* @param userId The UUID of the user to delete
|
|
24
|
+
* @param deletingId The UUID of the user performing the deletion (for authentication). Defaults to userId.
|
|
25
|
+
*/
|
|
26
|
+
export declare function deleteUser(userId: string, deletingId?: string): Promise<User>;
|
|
23
27
|
export declare function emailVerificationEnabled(userId: string): Promise<boolean>;
|
|
24
28
|
export declare function sendVerificationEmail(userId: string): Promise<Verification>;
|
|
25
29
|
export declare function verifyEmail(userId: string, token: string): Promise<void>;
|
package/dist/user.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { UserChangeable } from '@axium/core';
|
|
2
1
|
import { startAuthentication, startRegistration } from '@simplewebauthn/browser';
|
|
3
2
|
import * as z from 'zod';
|
|
4
3
|
import { fetchAPI } from './requests.js';
|
|
@@ -23,38 +22,20 @@ export async function loginByEmail(email) {
|
|
|
23
22
|
return await login(userId);
|
|
24
23
|
}
|
|
25
24
|
export async function getCurrentSession() {
|
|
26
|
-
|
|
27
|
-
result.created = new Date(result.created);
|
|
28
|
-
result.expires = new Date(result.expires);
|
|
29
|
-
return result;
|
|
25
|
+
return await fetchAPI('GET', 'session');
|
|
30
26
|
}
|
|
31
27
|
export async function getSessions(userId) {
|
|
32
28
|
_checkId(userId);
|
|
33
|
-
|
|
34
|
-
for (const session of result) {
|
|
35
|
-
session.created = new Date(session.created);
|
|
36
|
-
session.expires = new Date(session.expires);
|
|
37
|
-
}
|
|
38
|
-
return result;
|
|
29
|
+
return await fetchAPI('GET', 'users/:id/sessions', {}, userId);
|
|
39
30
|
}
|
|
40
31
|
export async function logout(userId, ...sessionId) {
|
|
41
32
|
_checkId(userId);
|
|
42
|
-
|
|
43
|
-
for (const session of result) {
|
|
44
|
-
session.created = new Date(session.created);
|
|
45
|
-
session.expires = new Date(session.expires);
|
|
46
|
-
}
|
|
47
|
-
return result;
|
|
33
|
+
return await fetchAPI('DELETE', 'users/:id/sessions', { id: sessionId }, userId);
|
|
48
34
|
}
|
|
49
35
|
export async function logoutAll(userId) {
|
|
50
36
|
_checkId(userId);
|
|
51
37
|
await elevate(userId);
|
|
52
|
-
|
|
53
|
-
for (const session of result) {
|
|
54
|
-
session.created = new Date(session.created);
|
|
55
|
-
session.expires = new Date(session.expires);
|
|
56
|
-
}
|
|
57
|
-
return result;
|
|
38
|
+
return await fetchAPI('DELETE', 'users/:id/sessions', { confirm_all: true }, userId);
|
|
58
39
|
}
|
|
59
40
|
export async function logoutCurrentSession() {
|
|
60
41
|
return await fetchAPI('DELETE', 'session');
|
|
@@ -80,59 +61,43 @@ function _checkId(userId) {
|
|
|
80
61
|
}
|
|
81
62
|
export async function userInfo(userId) {
|
|
82
63
|
_checkId(userId);
|
|
83
|
-
|
|
84
|
-
user.registeredAt = new Date(user.registeredAt);
|
|
85
|
-
user.emailVerified = user.emailVerified ? new Date(user.emailVerified) : null;
|
|
86
|
-
return user;
|
|
64
|
+
return await fetchAPI('GET', 'users/:id', {}, userId);
|
|
87
65
|
}
|
|
88
66
|
export async function updateUser(userId, data) {
|
|
89
67
|
_checkId(userId);
|
|
90
|
-
|
|
91
|
-
throw e instanceof z.core.$ZodError ? z.prettifyError(e) : e;
|
|
92
|
-
});
|
|
93
|
-
const result = await fetchAPI('PATCH', 'users/:id', body, userId);
|
|
94
|
-
result.registeredAt = new Date(result.registeredAt);
|
|
95
|
-
if (result.emailVerified)
|
|
96
|
-
result.emailVerified = new Date(result.emailVerified);
|
|
97
|
-
return result;
|
|
68
|
+
return await fetchAPI('PATCH', 'users/:id', data, userId);
|
|
98
69
|
}
|
|
99
70
|
export async function fullUserInfo(userId) {
|
|
100
71
|
_checkId(userId);
|
|
101
|
-
|
|
102
|
-
result.registeredAt = new Date(result.registeredAt);
|
|
103
|
-
result.emailVerified = new Date(result.emailVerified);
|
|
104
|
-
return result;
|
|
72
|
+
return await fetchAPI('GET', 'users/:id/full', {}, userId);
|
|
105
73
|
}
|
|
106
|
-
|
|
74
|
+
/**
|
|
75
|
+
* @param userId The UUID of the user to delete
|
|
76
|
+
* @param deletingId The UUID of the user performing the deletion (for authentication). Defaults to userId.
|
|
77
|
+
*/
|
|
78
|
+
export async function deleteUser(userId, deletingId = userId) {
|
|
107
79
|
_checkId(userId);
|
|
108
|
-
const options = await fetchAPI('OPTIONS', 'users/:id/auth', { type: 'action' },
|
|
80
|
+
const options = await fetchAPI('OPTIONS', 'users/:id/auth', { type: 'action' }, deletingId);
|
|
109
81
|
const response = await startAuthentication({ optionsJSON: options });
|
|
110
|
-
await fetchAPI('POST', 'users/:id/auth', response,
|
|
111
|
-
|
|
112
|
-
result.registeredAt = new Date(result.registeredAt);
|
|
113
|
-
result.emailVerified = new Date(result.emailVerified);
|
|
114
|
-
return result;
|
|
82
|
+
await fetchAPI('POST', 'users/:id/auth', response, deletingId);
|
|
83
|
+
return await fetchAPI('DELETE', 'users/:id', response, userId);
|
|
115
84
|
}
|
|
116
85
|
export async function emailVerificationEnabled(userId) {
|
|
117
86
|
_checkId(userId);
|
|
118
|
-
const { enabled } = await fetchAPI('OPTIONS', 'users/:id/
|
|
87
|
+
const { enabled } = await fetchAPI('OPTIONS', 'users/:id/verify/email', {}, userId);
|
|
119
88
|
return enabled;
|
|
120
89
|
}
|
|
121
90
|
export async function sendVerificationEmail(userId) {
|
|
122
91
|
_checkId(userId);
|
|
123
|
-
return await fetchAPI('GET', 'users/:id/
|
|
92
|
+
return await fetchAPI('GET', 'users/:id/verify/email', {}, userId);
|
|
124
93
|
}
|
|
125
94
|
export async function verifyEmail(userId, token) {
|
|
126
95
|
_checkId(userId);
|
|
127
|
-
await fetchAPI('POST', 'users/:id/
|
|
96
|
+
await fetchAPI('POST', 'users/:id/verify/email', { token }, userId);
|
|
128
97
|
}
|
|
129
98
|
export async function getPasskeys(userId) {
|
|
130
99
|
_checkId(userId);
|
|
131
|
-
|
|
132
|
-
for (const passkey of result) {
|
|
133
|
-
passkey.createdAt = new Date(passkey.createdAt);
|
|
134
|
-
}
|
|
135
|
-
return result;
|
|
100
|
+
return await fetchAPI('GET', 'users/:id/passkeys', {}, userId);
|
|
136
101
|
}
|
|
137
102
|
/**
|
|
138
103
|
* Create a new passkey for an existing user.
|
package/lib/FormDialog.svelte
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import Dialog from './Dialog.svelte';
|
|
3
2
|
import type { HTMLDialogAttributes } from 'svelte/elements';
|
|
4
3
|
|
|
5
4
|
let {
|
|
@@ -59,7 +58,7 @@
|
|
|
59
58
|
<button type="submit" class={['submit', submitDanger && 'danger']}>{submitText}</button>
|
|
60
59
|
{/snippet}
|
|
61
60
|
|
|
62
|
-
<
|
|
61
|
+
<dialog bind:this={dialog} {onclose} {...rest}>
|
|
63
62
|
{@render header?.()}
|
|
64
63
|
<form {onsubmit} class="main" method="dialog">
|
|
65
64
|
{#if error}
|
|
@@ -76,7 +75,7 @@
|
|
|
76
75
|
{/if}
|
|
77
76
|
</form>
|
|
78
77
|
{@render footer?.()}
|
|
79
|
-
</
|
|
78
|
+
</dialog>
|
|
80
79
|
|
|
81
80
|
<style>
|
|
82
81
|
.actions {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import ClipboardCopy from './ClipboardCopy.svelte';
|
|
3
|
+
|
|
4
|
+
const { url }: { url: string } = $props();
|
|
5
|
+
|
|
6
|
+
const href = $derived(new URL(url, location.origin).href);
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<pre class="URLText"><span>{href}</span><ClipboardCopy value={href} --size="16px" /></pre>
|
|
10
|
+
|
|
11
|
+
<style>
|
|
12
|
+
.URLText {
|
|
13
|
+
display: flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
justify-content: space-between;
|
|
16
|
+
|
|
17
|
+
span {
|
|
18
|
+
overflow-x: scroll;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
</style>
|
package/lib/index.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export { default as AccessControlDialog } from './AccessControlDialog.svelte';
|
|
2
2
|
export { default as AppMenu } from './AppMenu.svelte';
|
|
3
3
|
export { default as ClipboardCopy } from './ClipboardCopy.svelte';
|
|
4
|
-
export { default as Dialog } from './Dialog.svelte';
|
|
5
4
|
export { default as FormDialog } from './FormDialog.svelte';
|
|
6
5
|
export { default as Icon } from './Icon.svelte';
|
|
7
6
|
export { default as Login } from './Login.svelte';
|
|
@@ -14,6 +13,7 @@ export { default as Register } from './Register.svelte';
|
|
|
14
13
|
export { default as SessionList } from './SessionList.svelte';
|
|
15
14
|
export { default as Toast } from './Toast.svelte';
|
|
16
15
|
export { default as Upload } from './Upload.svelte';
|
|
16
|
+
export { default as URLText } from './URLText.svelte';
|
|
17
17
|
export { default as UserCard } from './UserCard.svelte';
|
|
18
18
|
export { default as UserMenu } from './UserMenu.svelte';
|
|
19
19
|
export { default as Version } from './Version.svelte';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axium/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"author": "James Prevett <jp@jamespre.dev>",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "individual",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"build": "tsc"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@axium/core": ">=0.
|
|
43
|
+
"@axium/core": ">=0.17.0",
|
|
44
44
|
"utilium": "^2.3.8",
|
|
45
45
|
"zod": "^4.0.5",
|
|
46
46
|
"svelte": "^5.36.0"
|
package/lib/Dialog.svelte
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { HTMLDialogAttributes } from 'svelte/elements';
|
|
3
|
-
|
|
4
|
-
let { children, dialog = $bindable(), ...rest }: { children(): any; dialog?: HTMLDialogElement } & HTMLDialogAttributes = $props();
|
|
5
|
-
</script>
|
|
6
|
-
|
|
7
|
-
<dialog bind:this={dialog} {...rest}>
|
|
8
|
-
{@render children()}
|
|
9
|
-
</dialog>
|
|
10
|
-
|
|
11
|
-
<!-- svelte-ignore css_unused_selector -->
|
|
12
|
-
<style>
|
|
13
|
-
dialog {
|
|
14
|
-
border-radius: 1em;
|
|
15
|
-
background: var(--bg-menu);
|
|
16
|
-
border: 1px solid #8888;
|
|
17
|
-
padding: 1em;
|
|
18
|
-
|
|
19
|
-
form {
|
|
20
|
-
display: contents;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
dialog::backdrop {
|
|
25
|
-
background: #0003;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
dialog[open] {
|
|
29
|
-
animation: zoom 0.25s cubic-bezier(0.35, 1.55, 0.65, 1);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
@keyframes zoom {
|
|
33
|
-
from {
|
|
34
|
-
transform: scale(0.95);
|
|
35
|
-
}
|
|
36
|
-
to {
|
|
37
|
-
transform: scale(1);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
dialog[open]::backdrop {
|
|
42
|
-
animation: fade 0.25s ease-out;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
@keyframes fade {
|
|
46
|
-
from {
|
|
47
|
-
opacity: 0;
|
|
48
|
-
}
|
|
49
|
-
to {
|
|
50
|
-
opacity: 1;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
</style>
|