@axium/storage 0.20.4 → 0.21.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/client/cli.js +1 -1
- package/dist/client/config.js +1 -1
- package/dist/client/local.js +1 -1
- package/dist/client/sync.js +1 -1
- package/dist/polyfills.js +1 -1
- package/dist/server/batch.js +2 -2
- package/dist/server/cli.js +1 -1
- package/dist/server/hooks.js +1 -1
- package/lib/List.svelte +2 -13
- package/lib/Preview.css +4 -0
- package/lib/Preview.svelte +41 -35
- package/package.json +3 -3
- package/routes/files/[id]/+page.svelte +30 -37
package/dist/client/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { configDir, session } from '@axium/client/cli/config';
|
|
2
2
|
import { formatBytes } from '@axium/core/format';
|
|
3
|
-
import * as io from '
|
|
3
|
+
import * as io from 'ioium/node';
|
|
4
4
|
import { Option, program } from 'commander';
|
|
5
5
|
import { statSync, unlinkSync } from 'node:fs';
|
|
6
6
|
import { stat } from 'node:fs/promises';
|
package/dist/client/config.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { configDir } from '@axium/client/cli/config';
|
|
2
|
-
import { debug, readJSON, writeJSON } from '
|
|
2
|
+
import { debug, readJSON, writeJSON } from 'ioium/node';
|
|
3
3
|
import { join } from 'node:path/posix';
|
|
4
4
|
import * as z from 'zod';
|
|
5
5
|
import { Sync } from './sync.js';
|
package/dist/client/local.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cacheDir, session } from '@axium/client/cli/config';
|
|
2
2
|
import { userInfo } from '@axium/client/user';
|
|
3
3
|
import { UserPublic } from '@axium/core';
|
|
4
|
-
import * as io from '
|
|
4
|
+
import * as io from 'ioium/node';
|
|
5
5
|
import { ENOENT, ENOTDIR } from 'node:constants';
|
|
6
6
|
import { stat } from 'node:fs/promises';
|
|
7
7
|
import { join } from 'node:path';
|
package/dist/client/sync.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { configDir, saveConfig } from '@axium/client/cli/config';
|
|
2
2
|
import { fetchAPI } from '@axium/client/requests';
|
|
3
|
-
import * as io from '
|
|
3
|
+
import * as io from 'ioium/node';
|
|
4
4
|
import mime from 'mime';
|
|
5
5
|
import { createHash } from 'node:crypto';
|
|
6
6
|
import * as fs from 'node:fs';
|
package/dist/polyfills.js
CHANGED
|
@@ -7,7 +7,7 @@ https://github.com/microsoft/TypeScript/issues/61695
|
|
|
7
7
|
|
|
8
8
|
@todo Remove when TypeScript 5.9 is released
|
|
9
9
|
*/
|
|
10
|
-
import { debug } from '
|
|
10
|
+
import { debug } from 'ioium';
|
|
11
11
|
Uint8Array.prototype.toHex ??=
|
|
12
12
|
(debug('Using a polyfill of Uint8Array.prototype.toHex'),
|
|
13
13
|
function toHex() {
|
package/dist/server/batch.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getConfig } from '@axium/core';
|
|
1
|
+
import { checkACL, getConfig } from '@axium/core';
|
|
2
2
|
import * as acl from '@axium/server/acl';
|
|
3
3
|
import { audit } from '@axium/server/audit';
|
|
4
4
|
import { requireSession } from '@axium/server/auth';
|
|
@@ -74,7 +74,7 @@ addRoute({
|
|
|
74
74
|
continue;
|
|
75
75
|
if (!item.acl || !item.acl.length)
|
|
76
76
|
error(403, 'Missing permission for item: ' + item.id);
|
|
77
|
-
|
|
77
|
+
checkACL(item.acl, changedIds.has(item.id) ? { write: true } : { manage: true });
|
|
78
78
|
error(403, 'Missing permission for item: ' + item.id);
|
|
79
79
|
}
|
|
80
80
|
if (limits.user_size &&
|
package/dist/server/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { formatBytes, parseByteSize } from '@axium/core';
|
|
2
|
-
import { io } from '@axium/core/node';
|
|
3
2
|
import { lookupUser } from '@axium/server/cli';
|
|
4
3
|
import { count, database } from '@axium/server/database';
|
|
5
4
|
import { Option, program } from 'commander';
|
|
5
|
+
import * as io from 'ioium/node';
|
|
6
6
|
import { styleText } from 'node:util';
|
|
7
7
|
import * as z from 'zod';
|
|
8
8
|
import { parseItem } from './db.js';
|
package/dist/server/hooks.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getConfig } from '@axium/core';
|
|
2
2
|
import { formatBytes } from '@axium/core/format';
|
|
3
|
-
import { done, start } from '
|
|
3
|
+
import { done, start } from 'ioium/node';
|
|
4
4
|
import { count, database } from '@axium/server/database';
|
|
5
5
|
import { mkdirSync } from 'node:fs';
|
|
6
6
|
import '../common.js';
|
package/lib/List.svelte
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import type { AccessControllable, UserPublic } from '@axium/core';
|
|
8
8
|
import { formatBytes } from '@axium/core/format';
|
|
9
9
|
import { forMime as iconForMime } from '@axium/core/icons';
|
|
10
|
-
import { errorText } from '
|
|
10
|
+
import { errorText } from 'ioium';
|
|
11
11
|
import { getDirectoryMetadata, updateItemMetadata } from '@axium/storage/client';
|
|
12
12
|
import { copyShortURL, formatItemName } from '@axium/storage/client/frontend';
|
|
13
13
|
import { StorageItemSorting, type StorageItemMetadata } from '@axium/storage/common';
|
|
@@ -123,18 +123,7 @@
|
|
|
123
123
|
{@render action('download', 'download', i)}
|
|
124
124
|
{@render action('trash', 'trash', i)}
|
|
125
125
|
</div>
|
|
126
|
-
<AccessControlDialog
|
|
127
|
-
bind:dialog={dialogs['share:' + item.id]}
|
|
128
|
-
{item}
|
|
129
|
-
itemType="storage"
|
|
130
|
-
editable={(item.acl?.find(
|
|
131
|
-
a =>
|
|
132
|
-
a.userId == user?.id ||
|
|
133
|
-
(a.role && user?.roles.includes(a.role)) ||
|
|
134
|
-
(a.tag && user?.tags?.includes(a.tag)) ||
|
|
135
|
-
(!a.userId && !a.role && !a.tag)
|
|
136
|
-
)?.manage as boolean | undefined) ?? true}
|
|
137
|
-
/>
|
|
126
|
+
<AccessControlDialog bind:dialog={dialogs['share:' + item.id]} {item} itemType="storage" {user} />
|
|
138
127
|
</div>
|
|
139
128
|
{:else}
|
|
140
129
|
<p class="list-empty">{emptyText}</p>
|
package/lib/Preview.css
CHANGED
package/lib/Preview.svelte
CHANGED
|
@@ -14,11 +14,14 @@
|
|
|
14
14
|
shareDialog,
|
|
15
15
|
previewDialog,
|
|
16
16
|
onDelete = () => {},
|
|
17
|
+
noTopBar,
|
|
17
18
|
}: {
|
|
18
19
|
item: StorageItemMetadata & AccessControllable;
|
|
19
20
|
shareDialog?: HTMLDialogElement;
|
|
20
21
|
previewDialog?: HTMLDialogElement;
|
|
21
22
|
onDelete?(): unknown;
|
|
23
|
+
/** Set when the preview is displayed for an item not inside a directory (e.g. when sharing links to files) */
|
|
24
|
+
noTopBar?: boolean;
|
|
22
25
|
} = $props();
|
|
23
26
|
|
|
24
27
|
const itemOpeners = openers.filter(opener => opener.types.includes(item.type));
|
|
@@ -32,44 +35,47 @@
|
|
|
32
35
|
</span>
|
|
33
36
|
{/snippet}
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
<div class="
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
{@render action('rename', 'pencil')}
|
|
55
|
-
{#if shareDialog}
|
|
56
|
-
<span class="icon-text preview-action" onclick={() => shareDialog.showModal()}>
|
|
57
|
-
<Icon i="user-group" />
|
|
58
|
-
</span>
|
|
38
|
+
{#if !noTopBar}
|
|
39
|
+
<div class="preview-top-bar">
|
|
40
|
+
<div class="title">{item.name}</div>
|
|
41
|
+
|
|
42
|
+
{#if itemOpeners.length}
|
|
43
|
+
{@const [first, ...others] = itemOpeners}
|
|
44
|
+
<div class="openers">
|
|
45
|
+
<span>{text('storage.Preview.open_with')} <a href={first.openURL(item)} target="_blank">{first.name}</a></span>
|
|
46
|
+
{#if others.length}
|
|
47
|
+
<Popover>
|
|
48
|
+
{#snippet toggle()}
|
|
49
|
+
<Icon i="caret-down" />
|
|
50
|
+
{/snippet}
|
|
51
|
+
{#each others as opener}
|
|
52
|
+
<a href={opener.openURL(item)} target="_blank">{opener.name}</a>
|
|
53
|
+
{/each}
|
|
54
|
+
</Popover>
|
|
55
|
+
{/if}
|
|
56
|
+
</div>
|
|
59
57
|
{/if}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
58
|
+
<div class="actions">
|
|
59
|
+
{@render action('rename', 'pencil')}
|
|
60
|
+
{#if shareDialog}
|
|
61
|
+
<span class="icon-text preview-action" onclick={() => shareDialog.showModal()}>
|
|
62
|
+
<Icon i="user-group" />
|
|
63
|
+
</span>
|
|
64
|
+
{/if}
|
|
65
|
+
{@render action('download', 'download')}
|
|
66
|
+
<span class="icon-text preview-action" onclick={() => copyShortURL(item)}>
|
|
67
|
+
<Icon i="link-horizontal" />
|
|
68
68
|
</span>
|
|
69
|
-
|
|
69
|
+
{@render action('trash', 'trash')}
|
|
70
|
+
{#if previewDialog}
|
|
71
|
+
<span class="icon-text preview-action mobile-hide" onclick={() => previewDialog.close()}>
|
|
72
|
+
<Icon i="xmark" --size="20px" />
|
|
73
|
+
</span>
|
|
74
|
+
{/if}
|
|
75
|
+
</div>
|
|
70
76
|
</div>
|
|
71
|
-
|
|
72
|
-
<div class=
|
|
77
|
+
{/if}
|
|
78
|
+
<div class={['preview-content', noTopBar && 'no-top-bar']}>
|
|
73
79
|
{#if item.type.startsWith('image/')}
|
|
74
80
|
<img src={item.dataURL} alt={item.name} />
|
|
75
81
|
{:else if item.type.startsWith('audio/')}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axium/storage",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"author": "James Prevett <axium@jamespre.dev>",
|
|
5
5
|
"description": "User file storage for Axium",
|
|
6
6
|
"funding": {
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"build": "tsc"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@axium/client": ">=0.
|
|
44
|
-
"@axium/core": ">=0.
|
|
43
|
+
"@axium/client": ">=0.20.0",
|
|
44
|
+
"@axium/core": ">=0.24.0",
|
|
45
45
|
"@axium/server": ">=0.39.0",
|
|
46
46
|
"@sveltejs/kit": "^2.27.3",
|
|
47
47
|
"utilium": "^2.6.3"
|
|
@@ -33,46 +33,35 @@
|
|
|
33
33
|
{text('page.files.restore')}
|
|
34
34
|
</button>
|
|
35
35
|
{:else}
|
|
36
|
-
<AccessControlDialog
|
|
37
|
-
bind:dialog={shareDialog}
|
|
38
|
-
{item}
|
|
39
|
-
itemType="storage"
|
|
40
|
-
editable={(item.acl?.find(
|
|
41
|
-
a =>
|
|
42
|
-
a.userId == user?.id ||
|
|
43
|
-
(a.role && user?.roles.includes(a.role)) ||
|
|
44
|
-
(a.tag && user?.tags?.includes(a.tag)) ||
|
|
45
|
-
(!a.userId && !a.role && !a.tag)
|
|
46
|
-
)?.manage as boolean | undefined) ?? true}
|
|
47
|
-
/>
|
|
36
|
+
<AccessControlDialog bind:dialog={shareDialog} {item} itemType="storage" {user} />
|
|
48
37
|
{#if item.parents}
|
|
49
38
|
<p class="parents" data-sveltekit-reload>
|
|
39
|
+
<a href="/files">~</a>
|
|
50
40
|
{#each item.parents as { id, name } (id)}<a href="/files/{id}">{name}</a>{/each}
|
|
51
41
|
</p>
|
|
52
42
|
{/if}
|
|
53
|
-
{#
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
{/snippet}
|
|
66
|
-
|
|
67
|
-
<div class="folder-actions">
|
|
68
|
-
{@render action('folder-arrow-up', text('page.files.back'), () => (location.href = parentHref))}
|
|
69
|
-
{@render action('pencil', text('page.files.rename'), () => dialogs.rename.showModal())}
|
|
70
|
-
{@render action('user-group', text('page.files.share'), () => shareDialog.showModal())}
|
|
71
|
-
{@render action('download', text('page.files.download'), () => dialogs.download.showModal())}
|
|
72
|
-
{@render action('link-horizontal', text('page.files.copy_link'), () => copyShortURL(item))}
|
|
73
|
-
{@render action('trash', text('page.files.trash'), () => dialogs.trash.showModal())}
|
|
74
|
-
</div>
|
|
43
|
+
{#snippet action(i: string, text: string, handler: (e: Event) => unknown)}
|
|
44
|
+
<button
|
|
45
|
+
class="icon-text"
|
|
46
|
+
onclick={e => {
|
|
47
|
+
e.preventDefault();
|
|
48
|
+
handler(e);
|
|
49
|
+
}}
|
|
50
|
+
>
|
|
51
|
+
<Icon {i} />
|
|
52
|
+
<span class="mobile-hide">{text}</span>
|
|
53
|
+
</button>
|
|
54
|
+
{/snippet}
|
|
75
55
|
|
|
56
|
+
<div class="folder-actions">
|
|
57
|
+
{@render action('folder-arrow-up', text('page.files.back'), () => (location.href = parentHref))}
|
|
58
|
+
{@render action('pencil', text('page.files.rename'), () => dialogs.rename.showModal())}
|
|
59
|
+
{@render action('user-group', text('page.files.share'), () => shareDialog.showModal())}
|
|
60
|
+
{@render action('download', text('page.files.download'), () => dialogs.download.showModal())}
|
|
61
|
+
{@render action('link-horizontal', text('page.files.copy_link'), () => copyShortURL(item))}
|
|
62
|
+
{@render action('trash', text('page.files.trash'), () => dialogs.trash.showModal())}
|
|
63
|
+
</div>
|
|
64
|
+
{#if item.type == 'inode/directory'}
|
|
76
65
|
<List appMode bind:items user={data.session?.user} />
|
|
77
66
|
<Add parentId={item.id} onAdd={item => items.push(item)} />
|
|
78
67
|
|
|
@@ -113,7 +102,7 @@
|
|
|
113
102
|
</FormDialog>
|
|
114
103
|
{:else}
|
|
115
104
|
<div class="preview-container">
|
|
116
|
-
<Preview {item} {shareDialog} onDelete={() => (location.href = parentHref)} />
|
|
105
|
+
<Preview {item} {shareDialog} onDelete={() => (location.href = parentHref)} noTopBar />
|
|
117
106
|
</div>
|
|
118
107
|
{/if}
|
|
119
108
|
{/if}
|
|
@@ -122,7 +111,11 @@
|
|
|
122
111
|
.preview-container {
|
|
123
112
|
position: relative;
|
|
124
113
|
width: 100%;
|
|
125
|
-
height: 100
|
|
114
|
+
height: calc(100% - 5em);
|
|
115
|
+
|
|
116
|
+
@media (width < 700px) {
|
|
117
|
+
height: calc(100% - 6em);
|
|
118
|
+
}
|
|
126
119
|
}
|
|
127
120
|
|
|
128
121
|
.folder-actions {
|
|
@@ -134,7 +127,7 @@
|
|
|
134
127
|
.parents {
|
|
135
128
|
margin-top: 0;
|
|
136
129
|
|
|
137
|
-
a::before {
|
|
130
|
+
a:not(:first-child)::before {
|
|
138
131
|
content: ' / ';
|
|
139
132
|
color: #888;
|
|
140
133
|
}
|