@kvman/kernel 0.4.7 → 0.4.9
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/http/byte-range.d.ts +12 -0
- package/dist/http/byte-range.d.ts.map +1 -0
- package/dist/http/byte-range.js +22 -0
- package/dist/http/byte-range.js.map +1 -0
- package/dist/http/file-routes.d.ts.map +1 -1
- package/dist/http/file-routes.js +11 -3
- package/dist/http/file-routes.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** What a download answers for its `Range` header. */
|
|
2
|
+
export type RangeAnswer = {
|
|
3
|
+
kind: 'whole';
|
|
4
|
+
} | {
|
|
5
|
+
kind: 'part';
|
|
6
|
+
first: number;
|
|
7
|
+
last: number;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'unsatisfiable';
|
|
10
|
+
};
|
|
11
|
+
export declare function rangeOf(header: string | undefined, size: number): RangeAnswer;
|
|
12
|
+
//# sourceMappingURL=byte-range.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-range.d.ts","sourceRoot":"","sources":["../../src/http/byte-range.ts"],"names":[],"mappings":"AAGA,sDAAsD;AACtD,MAAM,MAAM,WAAW,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC;AAIxH,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAa7E"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// One byte range of a download (plan 04 §4.1, ADR 0107, 13), so a video can seek: `bytes=<first>-<last>`,
|
|
2
|
+
// `bytes=<first>-`, or `bytes=-<suffix length>`. Anything else is the whole file.
|
|
3
|
+
const single = /^bytes=(\d*)-(\d*)$/;
|
|
4
|
+
export function rangeOf(header, size) {
|
|
5
|
+
const match = header === undefined ? null : single.exec(header.trim());
|
|
6
|
+
if (match === null)
|
|
7
|
+
return { kind: 'whole' };
|
|
8
|
+
const [, from = '', to = ''] = match;
|
|
9
|
+
if (from === '' && to === '')
|
|
10
|
+
return { kind: 'whole' };
|
|
11
|
+
if (from === '') {
|
|
12
|
+
const suffix = Number(to);
|
|
13
|
+
return suffix === 0 || size === 0 ? { kind: 'unsatisfiable' } : { kind: 'part', first: Math.max(0, size - suffix), last: size - 1 };
|
|
14
|
+
}
|
|
15
|
+
const first = Number(from);
|
|
16
|
+
if (to !== '' && Number(to) < first)
|
|
17
|
+
return { kind: 'whole' };
|
|
18
|
+
if (first >= size)
|
|
19
|
+
return { kind: 'unsatisfiable' };
|
|
20
|
+
return { kind: 'part', first, last: to === '' ? size - 1 : Math.min(Number(to), size - 1) };
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=byte-range.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-range.js","sourceRoot":"","sources":["../../src/http/byte-range.ts"],"names":[],"mappings":"AAAA,0GAA0G;AAC1G,kFAAkF;AAKlF,MAAM,MAAM,GAAG,qBAAqB,CAAC;AAErC,MAAM,UAAU,OAAO,CAAC,MAA0B,EAAE,IAAY;IAC9D,MAAM,KAAK,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACvE,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC7C,MAAM,CAAC,EAAE,IAAI,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,GAAG,KAAK,CAAC;IACrC,IAAI,IAAI,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACvD,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QAChB,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QAC1B,OAAO,MAAM,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC,EAAE,CAAC;IACtI,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,EAAE,KAAK,EAAE,IAAI,MAAM,CAAC,EAAE,CAAC,GAAG,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC9D,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;IACpD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC;AAC9F,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-routes.d.ts","sourceRoot":"","sources":["../../src/http/file-routes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"file-routes.d.ts","sourceRoot":"","sources":["../../src/http/file-routes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAqB3C,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAyBlE"}
|
package/dist/http/file-routes.js
CHANGED
|
@@ -4,10 +4,12 @@ import { Readable } from 'node:stream';
|
|
|
4
4
|
import { z } from '@kvman/sdk';
|
|
5
5
|
import { fileLimitBytes } from "../limits.js";
|
|
6
6
|
import { validationFailed } from "../store/json-values.js";
|
|
7
|
+
import { rangeOf } from "./byte-range.js";
|
|
7
8
|
import { answer } from "./envelope.js";
|
|
8
9
|
import { writeCapped } from "./request-body.js";
|
|
9
10
|
// Uploads and downloads (plan 04 §4.1, ADR 0009, 37–39): both name their workspace; an upload is the raw body; a
|
|
10
|
-
// download is always an attachment, so a browser never renders a file on kvman's origin.
|
|
11
|
+
// download is always an attachment, so a browser never renders a file on kvman's origin. A download answers one byte
|
|
12
|
+
// range, so a video can seek (ADR 0107, 13).
|
|
11
13
|
const uploadSchema = z.object({ name: z.string().min(1), workspaceId: z.string().min(1) });
|
|
12
14
|
const downloadSchema = z.object({ workspaceId: z.string().min(1) });
|
|
13
15
|
function parsedQuery(schema, query) {
|
|
@@ -39,8 +41,14 @@ export function registerFileRoutes(app, kernel) {
|
|
|
39
41
|
app.get('/api/files/:id', (c) => {
|
|
40
42
|
const { workspaceId } = parsedQuery(downloadSchema, c.req.query());
|
|
41
43
|
const file = kernel.web.file(c.req.param('id'), workspaceId);
|
|
42
|
-
const headers = { 'Content-Type': file.type, 'Content-
|
|
43
|
-
|
|
44
|
+
const headers = { 'Content-Type': file.type, 'Content-Disposition': attachment(file.name), 'X-Content-Type-Options': 'nosniff', 'Accept-Ranges': 'bytes' };
|
|
45
|
+
const range = rangeOf(c.req.header('range'), file.size);
|
|
46
|
+
if (range.kind === 'unsatisfiable')
|
|
47
|
+
return new Response(null, { status: 416, headers: { ...headers, 'Content-Range': `bytes */${String(file.size)}` } });
|
|
48
|
+
if (range.kind === 'whole')
|
|
49
|
+
return new Response(Readable.toWeb(createReadStream(kernel.web.filePath(file.id))), { headers: { ...headers, 'Content-Length': String(file.size) } });
|
|
50
|
+
const part = { 'Content-Length': String(range.last - range.first + 1), 'Content-Range': `bytes ${String(range.first)}-${String(range.last)}/${String(file.size)}` };
|
|
51
|
+
return new Response(Readable.toWeb(createReadStream(kernel.web.filePath(file.id), { start: range.first, end: range.last })), { status: 206, headers: { ...headers, ...part } });
|
|
44
52
|
});
|
|
45
53
|
app.get('/api/locales/:lang', (c) => answer({ catalog: kernel.catalog(c.req.param('lang')) }));
|
|
46
54
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-routes.js","sourceRoot":"","sources":["../../src/http/file-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,OAAO,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAE/B,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,iHAAiH;AACjH,
|
|
1
|
+
{"version":3,"file":"file-routes.js","sourceRoot":"","sources":["../../src/http/file-routes.ts"],"names":[],"mappings":"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"}
|