@axium/storage 0.20.1 → 0.20.3
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/server/raw.js +34 -98
- package/lib/Preview.css +110 -0
- package/lib/Preview.svelte +1 -113
- package/package.json +1 -1
package/dist/server/raw.js
CHANGED
|
@@ -1,55 +1,3 @@
|
|
|
1
|
-
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
-
if (value !== null && value !== void 0) {
|
|
3
|
-
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
-
var dispose, inner;
|
|
5
|
-
if (async) {
|
|
6
|
-
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
-
dispose = value[Symbol.asyncDispose];
|
|
8
|
-
}
|
|
9
|
-
if (dispose === void 0) {
|
|
10
|
-
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
-
dispose = value[Symbol.dispose];
|
|
12
|
-
if (async) inner = dispose;
|
|
13
|
-
}
|
|
14
|
-
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
-
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
-
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
-
}
|
|
18
|
-
else if (async) {
|
|
19
|
-
env.stack.push({ async: true });
|
|
20
|
-
}
|
|
21
|
-
return value;
|
|
22
|
-
};
|
|
23
|
-
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
-
return function (env) {
|
|
25
|
-
function fail(e) {
|
|
26
|
-
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
-
env.hasError = true;
|
|
28
|
-
}
|
|
29
|
-
var r, s = 0;
|
|
30
|
-
function next() {
|
|
31
|
-
while (r = env.stack.pop()) {
|
|
32
|
-
try {
|
|
33
|
-
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
-
if (r.dispose) {
|
|
35
|
-
var result = r.dispose.call(r.value);
|
|
36
|
-
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
-
}
|
|
38
|
-
else s |= 1;
|
|
39
|
-
}
|
|
40
|
-
catch (e) {
|
|
41
|
-
fail(e);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
-
if (env.hasError) throw env.error;
|
|
46
|
-
}
|
|
47
|
-
return next();
|
|
48
|
-
};
|
|
49
|
-
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
-
var e = new Error(message);
|
|
51
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
-
});
|
|
53
1
|
import { getConfig } from '@axium/core';
|
|
54
2
|
import { audit } from '@axium/server/audit';
|
|
55
3
|
import { authRequestForItem, requireSession } from '@axium/server/auth';
|
|
@@ -57,8 +5,9 @@ import { database } from '@axium/server/database';
|
|
|
57
5
|
import { error, withError } from '@axium/server/requests';
|
|
58
6
|
import { addRoute } from '@axium/server/routes';
|
|
59
7
|
import { createHash } from 'node:crypto';
|
|
60
|
-
import {
|
|
8
|
+
import { copyFileSync, createReadStream, renameSync, unlinkSync, writeFileSync, writeSync } from 'node:fs';
|
|
61
9
|
import { join } from 'node:path/posix';
|
|
10
|
+
import { Readable } from 'node:stream';
|
|
62
11
|
import * as z from 'zod';
|
|
63
12
|
import '../polyfills.js';
|
|
64
13
|
import { getLimits } from './config.js';
|
|
@@ -147,53 +96,40 @@ addRoute({
|
|
|
147
96
|
path: '/raw/storage/:id',
|
|
148
97
|
params: { id: z.uuid() },
|
|
149
98
|
async GET(request, { id: itemId }) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
.map(val => (val && Number.isSafeInteger(parseInt(val)) ? parseInt(val) : undefined));
|
|
167
|
-
start = typeof _start == 'number' ? _start : Number(item.size) - _end;
|
|
168
|
-
end = typeof _start == 'number' ? _end : end;
|
|
169
|
-
length = end - start + 1;
|
|
170
|
-
}
|
|
171
|
-
if (start >= item.size || end >= item.size || start > end || start < 0) {
|
|
172
|
-
return new Response(null, {
|
|
173
|
-
status: 416,
|
|
174
|
-
headers: { 'Content-Range': `bytes */${item.size}` },
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
const content = new Uint8Array(length);
|
|
178
|
-
readSync(fd, content, 0, length, start);
|
|
179
|
-
return new Response(content, {
|
|
180
|
-
status: BigInt(length) == item.size ? 200 : 206,
|
|
181
|
-
headers: {
|
|
182
|
-
'Content-Range': `bytes ${start}-${end}/${item.size}`,
|
|
183
|
-
'Accept-Ranges': 'bytes',
|
|
184
|
-
'Content-Length': String(length),
|
|
185
|
-
'Content-Type': item.type,
|
|
186
|
-
'Content-Disposition': contentDispositionFor(item.name),
|
|
187
|
-
},
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
catch (e_1) {
|
|
191
|
-
env_1.error = e_1;
|
|
192
|
-
env_1.hasError = true;
|
|
99
|
+
if (!getConfig('@axium/storage').enabled)
|
|
100
|
+
error(503, 'User storage is disabled');
|
|
101
|
+
const { item } = await authRequestForItem(request, 'storage', itemId, { read: true }, true);
|
|
102
|
+
if (item.trashedAt)
|
|
103
|
+
error(410, 'Trashed items can not be downloaded');
|
|
104
|
+
const path = join(getConfig('@axium/storage').data, item.id);
|
|
105
|
+
const range = request.headers.get('range');
|
|
106
|
+
let start = 0, end = Number(item.size - 1n), length = Number(item.size);
|
|
107
|
+
if (range) {
|
|
108
|
+
const [_start, _end = end] = range
|
|
109
|
+
.replace(/bytes=/, '')
|
|
110
|
+
.split('-')
|
|
111
|
+
.map(val => (val && Number.isSafeInteger(parseInt(val)) ? parseInt(val) : undefined));
|
|
112
|
+
start = typeof _start == 'number' ? _start : Number(item.size) - _end;
|
|
113
|
+
end = typeof _start == 'number' ? _end : end;
|
|
114
|
+
length = end - start + 1;
|
|
193
115
|
}
|
|
194
|
-
|
|
195
|
-
|
|
116
|
+
if (start >= item.size || end >= item.size || start > end || start < 0) {
|
|
117
|
+
return new Response(null, {
|
|
118
|
+
status: 416,
|
|
119
|
+
headers: { 'Content-Range': `bytes */${item.size}` },
|
|
120
|
+
});
|
|
196
121
|
}
|
|
122
|
+
const content = Readable.toWeb(createReadStream(path, { start, end }));
|
|
123
|
+
return new Response(content, {
|
|
124
|
+
status: BigInt(length) == item.size ? 200 : 206,
|
|
125
|
+
headers: {
|
|
126
|
+
'Content-Range': `bytes ${start}-${end}/${item.size}`,
|
|
127
|
+
'Accept-Ranges': 'bytes',
|
|
128
|
+
'Content-Length': String(length),
|
|
129
|
+
'Content-Type': item.type,
|
|
130
|
+
'Content-Disposition': contentDispositionFor(item.name),
|
|
131
|
+
},
|
|
132
|
+
});
|
|
197
133
|
},
|
|
198
134
|
async POST(request, { id: itemId }) {
|
|
199
135
|
if (!getConfig('@axium/storage').enabled)
|
package/lib/Preview.css
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
anchor-scope: --preview-openers;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.preview-action {
|
|
6
|
+
--size: 18px;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.preview-action:hover {
|
|
10
|
+
cursor: pointer;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.preview-top-bar {
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
gap: 1em;
|
|
17
|
+
justify-content: space-between;
|
|
18
|
+
padding: 0;
|
|
19
|
+
position: absolute;
|
|
20
|
+
inset: 0.5em 1em 0;
|
|
21
|
+
height: fit-content;
|
|
22
|
+
|
|
23
|
+
> div {
|
|
24
|
+
display: flex;
|
|
25
|
+
gap: 1em;
|
|
26
|
+
align-items: center;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.openers {
|
|
31
|
+
padding: 1em;
|
|
32
|
+
border: var(--border-accent);
|
|
33
|
+
border-radius: 1em;
|
|
34
|
+
height: 2em;
|
|
35
|
+
anchor-name: --preview-openers;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.openers :global([popover]) {
|
|
39
|
+
inset: anchor(bottom) anchor(right) auto anchor(left);
|
|
40
|
+
position-anchor: --preview-openers;
|
|
41
|
+
width: anchor-size(width);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.actions {
|
|
45
|
+
right: 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.preview-content {
|
|
49
|
+
position: absolute;
|
|
50
|
+
inset: 3em 10em 1em;
|
|
51
|
+
display: flex;
|
|
52
|
+
text-align: center;
|
|
53
|
+
align-items: center;
|
|
54
|
+
justify-content: center;
|
|
55
|
+
flex-direction: column;
|
|
56
|
+
|
|
57
|
+
.full-fill {
|
|
58
|
+
position: absolute;
|
|
59
|
+
inset: 0;
|
|
60
|
+
width: 100%;
|
|
61
|
+
height: 100%;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.preview-text {
|
|
65
|
+
white-space: pre-wrap;
|
|
66
|
+
overflow-y: scroll;
|
|
67
|
+
line-height: 1.6;
|
|
68
|
+
background-color: var(--bg-menu);
|
|
69
|
+
font-family: monospace;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
img,
|
|
73
|
+
video {
|
|
74
|
+
max-width: 100%;
|
|
75
|
+
max-height: 100%;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.no-preview {
|
|
80
|
+
display: flex;
|
|
81
|
+
flex-direction: column;
|
|
82
|
+
gap: 1em;
|
|
83
|
+
align-items: center;
|
|
84
|
+
justify-content: center;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@media (width < 700px) {
|
|
88
|
+
.preview-top-bar {
|
|
89
|
+
flex-direction: column;
|
|
90
|
+
|
|
91
|
+
.actions {
|
|
92
|
+
justify-content: space-around;
|
|
93
|
+
width: 100%;
|
|
94
|
+
|
|
95
|
+
.preview-action {
|
|
96
|
+
padding: 1em;
|
|
97
|
+
flex: 1 1 0;
|
|
98
|
+
border-radius: 1em;
|
|
99
|
+
border: var(--border-accent);
|
|
100
|
+
padding: 1em;
|
|
101
|
+
justify-content: center;
|
|
102
|
+
display: flex;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.preview-content {
|
|
108
|
+
inset: 10em 1em 0;
|
|
109
|
+
}
|
|
110
|
+
}
|
package/lib/Preview.svelte
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { copyShortURL } from '@axium/storage/client/frontend';
|
|
8
8
|
import type { StorageItemMetadata } from '@axium/storage/common';
|
|
9
9
|
import '@axium/storage/polyfills';
|
|
10
|
+
import './Preview.css';
|
|
10
11
|
|
|
11
12
|
const {
|
|
12
13
|
item,
|
|
@@ -144,116 +145,3 @@
|
|
|
144
145
|
>
|
|
145
146
|
<p>{text('storage.Preview.download_confirm')}</p>
|
|
146
147
|
</FormDialog>
|
|
147
|
-
|
|
148
|
-
<style>
|
|
149
|
-
:host {
|
|
150
|
-
anchor-scope: --preview-openers;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
.preview-action {
|
|
154
|
-
--size: 18px;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
.preview-action:hover {
|
|
158
|
-
cursor: pointer;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
.preview-top-bar {
|
|
162
|
-
display: flex;
|
|
163
|
-
align-items: center;
|
|
164
|
-
gap: 1em;
|
|
165
|
-
justify-content: space-between;
|
|
166
|
-
padding: 0;
|
|
167
|
-
position: absolute;
|
|
168
|
-
inset: 0.5em 1em 0;
|
|
169
|
-
height: fit-content;
|
|
170
|
-
|
|
171
|
-
> div {
|
|
172
|
-
display: flex;
|
|
173
|
-
gap: 1em;
|
|
174
|
-
align-items: center;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
.openers {
|
|
179
|
-
padding: 1em;
|
|
180
|
-
border: var(--border-accent);
|
|
181
|
-
border-radius: 1em;
|
|
182
|
-
height: 2em;
|
|
183
|
-
anchor-name: --preview-openers;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
.openers :global([popover]) {
|
|
187
|
-
inset: anchor(bottom) anchor(right) auto anchor(left);
|
|
188
|
-
position-anchor: --preview-openers;
|
|
189
|
-
width: anchor-size(width);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
.actions {
|
|
193
|
-
right: 0;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
.preview-content {
|
|
197
|
-
position: absolute;
|
|
198
|
-
inset: 3em 10em 1em;
|
|
199
|
-
display: flex;
|
|
200
|
-
text-align: center;
|
|
201
|
-
align-items: center;
|
|
202
|
-
justify-content: center;
|
|
203
|
-
flex-direction: column;
|
|
204
|
-
|
|
205
|
-
.full-fill {
|
|
206
|
-
position: absolute;
|
|
207
|
-
inset: 0;
|
|
208
|
-
width: 100%;
|
|
209
|
-
height: 100%;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
.preview-text {
|
|
213
|
-
white-space: pre-wrap;
|
|
214
|
-
overflow-y: scroll;
|
|
215
|
-
line-height: 1.6;
|
|
216
|
-
background-color: var(--bg-menu);
|
|
217
|
-
font-family: monospace;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
img,
|
|
221
|
-
video {
|
|
222
|
-
max-width: 100%;
|
|
223
|
-
max-height: 100%;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
.no-preview {
|
|
228
|
-
display: flex;
|
|
229
|
-
flex-direction: column;
|
|
230
|
-
gap: 1em;
|
|
231
|
-
align-items: center;
|
|
232
|
-
justify-content: center;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
@media (width < 700px) {
|
|
236
|
-
.preview-top-bar {
|
|
237
|
-
flex-direction: column;
|
|
238
|
-
|
|
239
|
-
.actions {
|
|
240
|
-
justify-content: space-around;
|
|
241
|
-
width: 100%;
|
|
242
|
-
|
|
243
|
-
.preview-action {
|
|
244
|
-
padding: 1em;
|
|
245
|
-
flex: 1 1 0;
|
|
246
|
-
border-radius: 1em;
|
|
247
|
-
border: var(--border-accent);
|
|
248
|
-
padding: 1em;
|
|
249
|
-
justify-content: center;
|
|
250
|
-
display: flex;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
.preview-content {
|
|
256
|
-
inset: 10em 1em 0;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
</style>
|