@mieweb/pulsevault 0.0.2 → 0.1.1
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/CHANGELOG.md +258 -0
- package/LICENSE +15 -39
- package/OPERATIONS.md +223 -0
- package/PROTOCOL.md +345 -0
- package/README.md +548 -122
- package/augment.d.ts +1 -0
- package/augment.js +3 -0
- package/core.d.ts +1 -0
- package/core.js +7 -0
- package/dist/app.d.ts +91 -34
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +23 -33
- package/dist/app.js.map +1 -1
- package/dist/augment.d.ts +14 -7
- package/dist/augment.d.ts.map +1 -1
- package/dist/augment.js.map +1 -1
- package/dist/core.d.ts +108 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +494 -0
- package/dist/core.js.map +1 -0
- package/dist/lib/authorize.d.ts +19 -0
- package/dist/lib/authorize.d.ts.map +1 -0
- package/dist/lib/authorize.js +2 -0
- package/dist/lib/authorize.js.map +1 -0
- package/dist/lib/capability-token.d.ts +80 -0
- package/dist/lib/capability-token.d.ts.map +1 -0
- package/dist/lib/capability-token.js +134 -0
- package/dist/lib/capability-token.js.map +1 -0
- package/dist/lib/checksum.d.ts +45 -0
- package/dist/lib/checksum.d.ts.map +1 -0
- package/dist/lib/checksum.js +105 -0
- package/dist/lib/checksum.js.map +1 -0
- package/dist/lib/deeplinks.d.ts +37 -21
- package/dist/lib/deeplinks.d.ts.map +1 -1
- package/dist/lib/deeplinks.js +54 -13
- package/dist/lib/deeplinks.js.map +1 -1
- package/dist/lib/errors.d.ts +7 -0
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +18 -0
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/magic.d.ts +30 -5
- package/dist/lib/magic.d.ts.map +1 -1
- package/dist/lib/magic.js +51 -14
- package/dist/lib/magic.js.map +1 -1
- package/dist/lib/options.d.ts +41 -0
- package/dist/lib/options.d.ts.map +1 -0
- package/dist/lib/options.js +111 -0
- package/dist/lib/options.js.map +1 -0
- package/dist/lib/pulsevaultTus.d.ts +53 -26
- package/dist/lib/pulsevaultTus.d.ts.map +1 -1
- package/dist/lib/pulsevaultTus.js +174 -55
- package/dist/lib/pulsevaultTus.js.map +1 -1
- package/dist/lib/request.d.ts +26 -0
- package/dist/lib/request.d.ts.map +1 -0
- package/dist/lib/request.js +22 -0
- package/dist/lib/request.js.map +1 -0
- package/dist/lib/uuid.d.ts.map +1 -1
- package/dist/lib/uuid.js +1 -1
- package/dist/lib/uuid.js.map +1 -1
- package/dist/routes/pulsevault.d.ts +18 -16
- package/dist/routes/pulsevault.d.ts.map +1 -1
- package/dist/routes/pulsevault.js +121 -251
- package/dist/routes/pulsevault.js.map +1 -1
- package/dist/storage/local.d.ts +31 -10
- package/dist/storage/local.d.ts.map +1 -1
- package/dist/storage/local.js +205 -84
- package/dist/storage/local.js.map +1 -1
- package/dist/storage/s3.d.ts +109 -0
- package/dist/storage/s3.d.ts.map +1 -0
- package/dist/storage/s3.js +438 -0
- package/dist/storage/s3.js.map +1 -0
- package/dist/storage/types.d.ts +80 -17
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/storage/types.js +13 -1
- package/dist/storage/types.js.map +1 -1
- package/package.json +29 -7
package/dist/storage/local.js
CHANGED
|
@@ -1,51 +1,135 @@
|
|
|
1
|
-
import { FileStore } from
|
|
2
|
-
import fs from
|
|
3
|
-
import path from
|
|
4
|
-
|
|
1
|
+
import { FileStore } from '@tus/file-store';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { isUuid } from '../lib/uuid.js';
|
|
5
|
+
import { parseUploadKind } from './types.js';
|
|
5
6
|
const SIDECAR_VERSION = 1;
|
|
7
|
+
/** Hidden directory inside workspaceRoot that holds per-upload sidecar files. */
|
|
8
|
+
const PULSEVAULT_META_DIR = '.pulsevault';
|
|
9
|
+
/** Default cap on the in-memory metadata cache before evicting the oldest entry. */
|
|
10
|
+
const DEFAULT_META_CACHE_LIMIT = 10_000;
|
|
11
|
+
/** Map a file extension to the `Content-Type` the GET route should return. */
|
|
12
|
+
function extToContentType(ext) {
|
|
13
|
+
switch (ext) {
|
|
14
|
+
case '.mp4':
|
|
15
|
+
return 'video/mp4';
|
|
16
|
+
case '.zip':
|
|
17
|
+
return 'application/zip';
|
|
18
|
+
case '.vtt':
|
|
19
|
+
return 'text/vtt';
|
|
20
|
+
case '.jpg':
|
|
21
|
+
case '.jpeg':
|
|
22
|
+
return 'image/jpeg';
|
|
23
|
+
case '.png':
|
|
24
|
+
return 'image/png';
|
|
25
|
+
default:
|
|
26
|
+
return 'application/octet-stream';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** Project a `Sidecar` into the shape kept in the in-memory cache. */
|
|
30
|
+
function sidecarToCachedMeta(sidecar, ready) {
|
|
31
|
+
return {
|
|
32
|
+
ext: sidecar.ext,
|
|
33
|
+
ready,
|
|
34
|
+
kind: sidecar.kind ?? 'video',
|
|
35
|
+
relatedTo: sidecar.relatedTo,
|
|
36
|
+
checksum: sidecar.checksum,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
6
39
|
export function createLocalStorage(opts) {
|
|
7
40
|
const workspaceRoot = path.resolve(opts.workspaceDir);
|
|
8
41
|
const datastore = new FileStore({ directory: workspaceRoot });
|
|
9
|
-
|
|
10
|
-
//
|
|
11
|
-
//
|
|
42
|
+
const metaCacheLimit = opts.metaCacheLimit ?? DEFAULT_META_CACHE_LIMIT;
|
|
43
|
+
// Metadata cache keyed by artifactId. Populated eagerly on reserve and
|
|
44
|
+
// lazily from the sidecar on cache-miss — so we never do a workspace-wide
|
|
45
|
+
// scan at boot and never do a per-request readdir on the GET hot path.
|
|
46
|
+
// Bounded with simple insertion-order eviction (a `Map` preserves insertion
|
|
47
|
+
// order, and re-setting a key moves it to the end) so a long-running server
|
|
48
|
+
// doesn't grow this unboundedly; a cache miss just costs an extra disk read.
|
|
12
49
|
const metaCache = new Map();
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
50
|
+
const cacheSet = (artifactId, meta) => {
|
|
51
|
+
// Re-inserting moves the key to the end of iteration order, so eviction
|
|
52
|
+
// below always drops the actual least-recently-set entry.
|
|
53
|
+
metaCache.delete(artifactId);
|
|
54
|
+
metaCache.set(artifactId, meta);
|
|
55
|
+
if (metaCache.size > metaCacheLimit) {
|
|
56
|
+
const oldest = metaCache.keys().next().value;
|
|
57
|
+
if (oldest !== undefined)
|
|
58
|
+
metaCache.delete(oldest);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
/** Absolute path to the hidden metadata directory. */
|
|
62
|
+
const sidecarDir = () => path.join(workspaceRoot, PULSEVAULT_META_DIR);
|
|
63
|
+
/**
|
|
64
|
+
* Absolute path to the sidecar JSON for a given artifactId. `readSidecar`
|
|
65
|
+
* already rejects non-UUID ids before any path is built; the resolve +
|
|
66
|
+
* containment check here is defense in depth for any future caller that
|
|
67
|
+
* bypasses that funnel — a path that escapes the metadata directory is a
|
|
68
|
+
* hard error, never a read.
|
|
69
|
+
*/
|
|
70
|
+
const sidecarPath = (artifactId) => {
|
|
71
|
+
// Strictly inside the metadata directory: the sidecar is always a `.json`
|
|
72
|
+
// file under it, so the resolved path can never equal the directory itself.
|
|
73
|
+
const base = path.resolve(sidecarDir());
|
|
74
|
+
const resolved = path.resolve(base, `${artifactId}.json`);
|
|
75
|
+
if (!resolved.startsWith(`${base}${path.sep}`)) {
|
|
76
|
+
throw new Error('artifactId escapes the metadata directory');
|
|
77
|
+
}
|
|
78
|
+
return resolved;
|
|
79
|
+
};
|
|
80
|
+
/** Relative path (from workspaceRoot) to the artifact bytes. */
|
|
81
|
+
const artifactRelPath = (artifactId, kind, ext) => `${kind}/${artifactId}${ext}`;
|
|
82
|
+
const writeSidecar = async (artifactId, sidecar) => {
|
|
17
83
|
// Atomic tmp + rename so a crash mid-write can never leave a truncated
|
|
18
84
|
// JSON blob that `loadMeta` would then treat as corrupt.
|
|
19
|
-
const finalPath = sidecarPath(
|
|
85
|
+
const finalPath = sidecarPath(artifactId);
|
|
20
86
|
const tmpPath = `${finalPath}.tmp`;
|
|
21
|
-
await fs.
|
|
87
|
+
await fs.mkdir(sidecarDir(), { recursive: true, mode: 0o750 });
|
|
88
|
+
await fs.writeFile(tmpPath, JSON.stringify(sidecar), 'utf8');
|
|
22
89
|
await fs.rename(tmpPath, finalPath);
|
|
23
90
|
};
|
|
24
|
-
const readSidecar = async (
|
|
91
|
+
const readSidecar = async (artifactId) => {
|
|
92
|
+
// Every sidecar/artifact path in this module is built by joining
|
|
93
|
+
// `artifactId` straight into a filesystem path — reject anything that
|
|
94
|
+
// isn't a real UUID before it reaches `fs`, the same way `resolve()`
|
|
95
|
+
// already refuses to serve non-UUID ids, so a stray `../` (or one
|
|
96
|
+
// smuggled in by a caller that skips the HTTP route layer, e.g. a
|
|
97
|
+
// direct `getLocalPath`/`getKind` call) can never escape the intended
|
|
98
|
+
// `.pulsevault`/`<kind>` subdirectories. This is the single funnel
|
|
99
|
+
// every other method in this file goes through (`loadMeta`), so
|
|
100
|
+
// gating here covers `getLocalPath`, `getKind`, `getRelatedTo`,
|
|
101
|
+
// `getChecksum`, `resolve`, `remove`, and `markReady` in one place.
|
|
102
|
+
if (!isUuid(artifactId))
|
|
103
|
+
return null;
|
|
25
104
|
let raw;
|
|
26
105
|
try {
|
|
27
|
-
raw = await fs.readFile(sidecarPath(
|
|
106
|
+
raw = await fs.readFile(sidecarPath(artifactId), 'utf8');
|
|
28
107
|
}
|
|
29
108
|
catch (err) {
|
|
30
|
-
if (err?.code ===
|
|
109
|
+
if (err?.code === 'ENOENT')
|
|
31
110
|
return null;
|
|
32
111
|
throw err;
|
|
33
112
|
}
|
|
34
113
|
try {
|
|
35
114
|
const parsed = JSON.parse(raw);
|
|
36
|
-
if (typeof parsed.ext !==
|
|
115
|
+
if (typeof parsed.ext !== 'string')
|
|
37
116
|
return null;
|
|
38
|
-
if (typeof parsed.filename !==
|
|
117
|
+
if (typeof parsed.filename !== 'string')
|
|
39
118
|
return null;
|
|
40
119
|
// Older sidecars (pre-status) are treated as ready so an in-place
|
|
41
120
|
// upgrade doesn't hide finalized uploads. New uploads always write a
|
|
42
121
|
// `status` field explicitly.
|
|
43
|
-
const status = parsed.status ===
|
|
122
|
+
const status = parsed.status === 'uploading' ? 'uploading' : 'ready';
|
|
123
|
+
// Older sidecars without `kind` default to `"video"` — no migration.
|
|
124
|
+
const kind = parseUploadKind(parsed.kind);
|
|
44
125
|
return {
|
|
45
126
|
version: SIDECAR_VERSION,
|
|
46
127
|
ext: parsed.ext,
|
|
47
128
|
filename: parsed.filename,
|
|
48
129
|
status,
|
|
130
|
+
kind,
|
|
131
|
+
relatedTo: typeof parsed.relatedTo === 'string' ? parsed.relatedTo : undefined,
|
|
132
|
+
checksum: typeof parsed.checksum === 'string' ? parsed.checksum : undefined,
|
|
49
133
|
};
|
|
50
134
|
}
|
|
51
135
|
catch {
|
|
@@ -54,104 +138,138 @@ export function createLocalStorage(opts) {
|
|
|
54
138
|
return null;
|
|
55
139
|
}
|
|
56
140
|
};
|
|
57
|
-
const loadMeta = async (
|
|
58
|
-
const cached = metaCache.get(
|
|
141
|
+
const loadMeta = async (artifactId) => {
|
|
142
|
+
const cached = metaCache.get(artifactId);
|
|
59
143
|
if (cached)
|
|
60
144
|
return cached;
|
|
61
|
-
const sidecar = await readSidecar(
|
|
145
|
+
const sidecar = await readSidecar(artifactId);
|
|
62
146
|
if (!sidecar)
|
|
63
147
|
return null;
|
|
64
|
-
const meta =
|
|
65
|
-
|
|
66
|
-
ready: sidecar.status === "ready",
|
|
67
|
-
};
|
|
68
|
-
metaCache.set(videoid, meta);
|
|
148
|
+
const meta = sidecarToCachedMeta(sidecar, sidecar.status === 'ready');
|
|
149
|
+
cacheSet(artifactId, meta);
|
|
69
150
|
return meta;
|
|
70
151
|
};
|
|
71
152
|
const initialize = async () => {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const dir = videoDir(videoid);
|
|
85
|
-
await fs.mkdir(path.join(dir, "video"), { recursive: true });
|
|
86
|
-
await writeSidecar(videoid, {
|
|
153
|
+
// Dirs PulseVault creates itself get mode 0o750 directly (mkdir's mode caps
|
|
154
|
+
// the permission bits — umask only removes more — so this holds even under a
|
|
155
|
+
// permissive umask; a world-readable upload tree would otherwise leak media).
|
|
156
|
+
await fs.mkdir(sidecarDir(), { recursive: true, mode: 0o750 });
|
|
157
|
+
// @tus/file-store creates `workspaceRoot` with mode 0777 if it doesn't already exist;
|
|
158
|
+
// tighten it so the upload tree isn't world-writable under a permissive umask.
|
|
159
|
+
await fs.chmod(workspaceRoot, 0o750).catch(() => { });
|
|
160
|
+
};
|
|
161
|
+
const reserveUpload = async ({ artifactId, filename, ext, kind, relatedTo, checksum, }) => {
|
|
162
|
+
await fs.mkdir(path.join(workspaceRoot, kind), { recursive: true, mode: 0o750 });
|
|
163
|
+
await fs.mkdir(sidecarDir(), { recursive: true, mode: 0o750 });
|
|
164
|
+
const sidecar = {
|
|
87
165
|
version: SIDECAR_VERSION,
|
|
88
166
|
ext,
|
|
89
167
|
filename,
|
|
90
|
-
status:
|
|
91
|
-
|
|
92
|
-
|
|
168
|
+
status: 'uploading',
|
|
169
|
+
kind,
|
|
170
|
+
relatedTo,
|
|
171
|
+
checksum,
|
|
172
|
+
};
|
|
173
|
+
// Collision guard: `wx` fails atomically with EEXIST if a sidecar already exists for
|
|
174
|
+
// this artifactId, rather than the previous read-then-write (`loadMeta` then
|
|
175
|
+
// `writeSidecar`) which left a window for two concurrent/retried requests to both pass
|
|
176
|
+
// the check before either had written — letting the second silently clobber the first's
|
|
177
|
+
// sidecar and race @tus/file-store's own offset tracking. Translates to HTTP 409 via
|
|
178
|
+
// @tus/server's error path, same as before.
|
|
179
|
+
try {
|
|
180
|
+
await fs.writeFile(sidecarPath(artifactId), JSON.stringify(sidecar), { flag: 'wx' });
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
if (err?.code !== 'EEXIST')
|
|
184
|
+
throw err;
|
|
185
|
+
// A file already exists at this path, but `readSidecar` treats a malformed/corrupt
|
|
186
|
+
// one as absent (e.g. debris from a crash mid-write) — re-check before deciding this
|
|
187
|
+
// is a genuine collision rather than debris that's safe to overwrite.
|
|
188
|
+
const existing = await readSidecar(artifactId);
|
|
189
|
+
if (existing) {
|
|
190
|
+
throw Object.assign(new Error(`artifactId ${artifactId} already has an upload`), {
|
|
191
|
+
statusCode: 409,
|
|
192
|
+
status_code: 409,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
await writeSidecar(artifactId, sidecar);
|
|
196
|
+
}
|
|
197
|
+
cacheSet(artifactId, { ext, ready: false, kind, relatedTo, checksum });
|
|
93
198
|
// @tus/file-store joins this onto its configured `directory`, so the
|
|
94
|
-
// actual file lands at `<workspaceRoot>/<
|
|
95
|
-
return
|
|
199
|
+
// actual file lands at `<workspaceRoot>/<kind>/<artifactId><ext>`.
|
|
200
|
+
return artifactRelPath(artifactId, kind, ext);
|
|
96
201
|
};
|
|
97
|
-
const resolve = async (
|
|
98
|
-
const meta = await loadMeta(
|
|
202
|
+
const resolve = async (artifactId) => {
|
|
203
|
+
const meta = await loadMeta(artifactId);
|
|
99
204
|
// Only serve ready uploads. In-progress uploads stay hidden — a client
|
|
100
205
|
// GETting mid-upload would otherwise receive a truncated file.
|
|
101
206
|
if (!meta || !meta.ready)
|
|
102
207
|
return null;
|
|
103
|
-
const
|
|
104
|
-
const relFile = videoRelPath(videoid, meta.ext);
|
|
208
|
+
const relFile = artifactRelPath(artifactId, meta.kind, meta.ext);
|
|
105
209
|
try {
|
|
106
|
-
const stat = await fs.stat(path.join(
|
|
210
|
+
const stat = await fs.stat(path.join(workspaceRoot, relFile));
|
|
107
211
|
if (!stat.isFile())
|
|
108
212
|
return null;
|
|
109
213
|
}
|
|
110
214
|
catch (err) {
|
|
111
|
-
if (err?.code ===
|
|
215
|
+
if (err?.code === 'ENOENT')
|
|
112
216
|
return null;
|
|
113
217
|
throw err;
|
|
114
218
|
}
|
|
115
|
-
return {
|
|
219
|
+
return {
|
|
220
|
+
kind: 'stream',
|
|
221
|
+
root: workspaceRoot,
|
|
222
|
+
filename: relFile,
|
|
223
|
+
contentType: extToContentType(meta.ext),
|
|
224
|
+
};
|
|
116
225
|
};
|
|
117
|
-
const markReady = async (
|
|
118
|
-
const sidecar = await readSidecar(
|
|
226
|
+
const markReady = async (artifactId) => {
|
|
227
|
+
const sidecar = await readSidecar(artifactId);
|
|
119
228
|
if (!sidecar) {
|
|
120
|
-
// No sidecar means no `reserveUpload` happened for this
|
|
121
|
-
// is a contract violation by the caller, not a recoverable state.
|
|
122
|
-
throw new Error(`markReady: no sidecar for
|
|
229
|
+
// No sidecar means no `reserveUpload` happened for this artifactId —
|
|
230
|
+
// this is a contract violation by the caller, not a recoverable state.
|
|
231
|
+
throw new Error(`markReady: no sidecar for artifactId ${artifactId} (was reserveUpload called?)`);
|
|
123
232
|
}
|
|
124
|
-
if (sidecar.status ===
|
|
233
|
+
if (sidecar.status === 'ready') {
|
|
125
234
|
// Idempotent: already ready is fine, keep the cache consistent.
|
|
126
|
-
|
|
235
|
+
cacheSet(artifactId, sidecarToCachedMeta(sidecar, true));
|
|
127
236
|
return;
|
|
128
237
|
}
|
|
129
|
-
await writeSidecar(
|
|
130
|
-
|
|
131
|
-
};
|
|
132
|
-
const remove = async (
|
|
133
|
-
const
|
|
134
|
-
// Drop from cache before
|
|
135
|
-
//
|
|
136
|
-
metaCache.delete(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
return false;
|
|
147
|
-
throw err;
|
|
148
|
-
}
|
|
238
|
+
await writeSidecar(artifactId, { ...sidecar, status: 'ready' });
|
|
239
|
+
cacheSet(artifactId, sidecarToCachedMeta(sidecar, true));
|
|
240
|
+
};
|
|
241
|
+
const remove = async (artifactId) => {
|
|
242
|
+
const meta = await loadMeta(artifactId);
|
|
243
|
+
// Drop from cache before rm so a racing `resolve` arriving after the
|
|
244
|
+
// rm but before cache eviction can't hand back a stale path.
|
|
245
|
+
metaCache.delete(artifactId);
|
|
246
|
+
if (!meta)
|
|
247
|
+
return false;
|
|
248
|
+
const artifactPath = path.join(workspaceRoot, meta.kind, `${artifactId}${meta.ext}`);
|
|
249
|
+
await Promise.all([
|
|
250
|
+
fs.rm(artifactPath, { force: true }),
|
|
251
|
+
fs.rm(`${artifactPath}.json`, { force: true }),
|
|
252
|
+
fs.rm(sidecarPath(artifactId), { force: true }),
|
|
253
|
+
]);
|
|
254
|
+
return true;
|
|
149
255
|
};
|
|
150
|
-
const getLocalPath = async (
|
|
151
|
-
const meta = await loadMeta(
|
|
256
|
+
const getLocalPath = async (artifactId) => {
|
|
257
|
+
const meta = await loadMeta(artifactId);
|
|
152
258
|
if (!meta)
|
|
153
259
|
return null;
|
|
154
|
-
return path.join(workspaceRoot,
|
|
260
|
+
return path.join(workspaceRoot, meta.kind, `${artifactId}${meta.ext}`);
|
|
261
|
+
};
|
|
262
|
+
const getKind = async (artifactId) => {
|
|
263
|
+
const meta = await loadMeta(artifactId);
|
|
264
|
+
return meta ? meta.kind : null;
|
|
265
|
+
};
|
|
266
|
+
const getRelatedTo = async (artifactId) => {
|
|
267
|
+
const meta = await loadMeta(artifactId);
|
|
268
|
+
return meta?.relatedTo ?? null;
|
|
269
|
+
};
|
|
270
|
+
const getChecksum = async (artifactId) => {
|
|
271
|
+
const meta = await loadMeta(artifactId);
|
|
272
|
+
return meta?.checksum ?? null;
|
|
155
273
|
};
|
|
156
274
|
return {
|
|
157
275
|
datastore,
|
|
@@ -162,6 +280,9 @@ export function createLocalStorage(opts) {
|
|
|
162
280
|
markReady,
|
|
163
281
|
remove,
|
|
164
282
|
getLocalPath,
|
|
283
|
+
getKind,
|
|
284
|
+
getRelatedTo,
|
|
285
|
+
getChecksum,
|
|
165
286
|
};
|
|
166
287
|
}
|
|
167
288
|
//# sourceMappingURL=local.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/storage/local.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/storage/local.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { S3ClientConfig } from '@aws-sdk/client-s3';
|
|
2
|
+
import type { PulseVaultStorage, UploadKind } from './types.js';
|
|
3
|
+
export type S3StorageOptions = {
|
|
4
|
+
/** Target bucket. Must already exist (the integrator provisions it). */
|
|
5
|
+
bucket: string;
|
|
6
|
+
/**
|
|
7
|
+
* Custom S3 endpoint. Set this for Cloudflare R2 or any S3-compatible store
|
|
8
|
+
* (e.g. `https://<account-id>.r2.cloudflarestorage.com`). Omit for AWS S3.
|
|
9
|
+
*/
|
|
10
|
+
endpoint?: string;
|
|
11
|
+
/**
|
|
12
|
+
* AWS region. Required for AWS S3; for R2 use `"auto"`. When omitted and an
|
|
13
|
+
* `endpoint` is set this defaults to `"auto"`; otherwise the SDK resolves it
|
|
14
|
+
* from the environment.
|
|
15
|
+
*/
|
|
16
|
+
region?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Access key id. Optional — when both `accessKeyId` and `secretAccessKey`
|
|
19
|
+
* are omitted the AWS SDK default credential chain is used (env vars, IAM
|
|
20
|
+
* role, etc.). Never hard-code keys; read them from env in your app.
|
|
21
|
+
*/
|
|
22
|
+
accessKeyId?: string;
|
|
23
|
+
/** Secret access key. See `accessKeyId`. */
|
|
24
|
+
secretAccessKey?: string;
|
|
25
|
+
/** Optional STS session token for temporary credentials. */
|
|
26
|
+
sessionToken?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Use path-style addressing (`<endpoint>/<bucket>/<key>`) instead of
|
|
29
|
+
* virtual-host style. Defaults to `true` whenever a custom `endpoint` is set
|
|
30
|
+
* (R2 and most S3-compatible stores need it).
|
|
31
|
+
*/
|
|
32
|
+
forcePathStyle?: boolean;
|
|
33
|
+
/** Presigned playback URL TTL in seconds. Defaults to 900 (15 minutes). */
|
|
34
|
+
presignTtlSeconds?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Preferred multipart part size in bytes, forwarded to `@tus/s3-store`. Must
|
|
37
|
+
* be >= 5 MiB. When omitted, `@tus/s3-store` computes an optimal size.
|
|
38
|
+
*/
|
|
39
|
+
partSize?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Max number of entries kept in the in-memory metadata cache before the
|
|
42
|
+
* oldest (by insertion order) is evicted. A cache miss falls back to a
|
|
43
|
+
* bucket read, so eviction only costs an extra request, not correctness.
|
|
44
|
+
* Defaults to 10,000.
|
|
45
|
+
*/
|
|
46
|
+
metaCacheLimit?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Advanced escape hatch: extra `S3ClientConfig` fields merged into the
|
|
49
|
+
* client used for both playback presigning and the underlying TUS datastore
|
|
50
|
+
* (e.g. checksum flags for S3-compatible stores). Values here win over the
|
|
51
|
+
* fields derived from the options above.
|
|
52
|
+
*/
|
|
53
|
+
clientConfig?: Partial<S3ClientConfig>;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* S3 / Cloudflare R2 storage adapter. Uploads stream into the bucket via S3
|
|
57
|
+
* multipart upload (`@tus/s3-store`); playback is served by redirecting the
|
|
58
|
+
* client to a short-lived presigned GET URL, so bytes never flow back through
|
|
59
|
+
* the app server.
|
|
60
|
+
*/
|
|
61
|
+
export type S3Storage = PulseVaultStorage & {
|
|
62
|
+
/** The bucket this adapter writes to. */
|
|
63
|
+
readonly bucket: string;
|
|
64
|
+
/**
|
|
65
|
+
* Ranged GET of the first `n` bytes of a finalized upload, or `null` if the
|
|
66
|
+
* artifactId is unknown. Used by `createS3Mp4Sniffer` to validate the
|
|
67
|
+
* payload without downloading the whole object.
|
|
68
|
+
*/
|
|
69
|
+
readHeader(artifactId: string, n: number): Promise<Buffer | null>;
|
|
70
|
+
/**
|
|
71
|
+
* Full GET of a finalized upload's bytes, or `null` if the artifactId is
|
|
72
|
+
* unknown. Used by `createS3ChecksumValidator` — unlike `readHeader`, this
|
|
73
|
+
* downloads the whole object, so it's only worth using for an explicit,
|
|
74
|
+
* opt-in integrity check, not on every upload by default.
|
|
75
|
+
*/
|
|
76
|
+
readAll(artifactId: string): Promise<Buffer | null>;
|
|
77
|
+
/**
|
|
78
|
+
* Streams a finalized upload's bytes through a hash digest, returning the
|
|
79
|
+
* hex digest, or `null` if the artifactId is unknown. The streaming
|
|
80
|
+
* counterpart to `readAll` — used by `createS3ChecksumValidator` so
|
|
81
|
+
* checksum verification never has to hold an entire (potentially
|
|
82
|
+
* multi-gigabyte) object in memory as one `Buffer`.
|
|
83
|
+
*/
|
|
84
|
+
digestAll(artifactId: string, algorithm: 'sha256' | 'sha1' | 'md5'): Promise<string | null>;
|
|
85
|
+
/** Artifact kind for a known artifactId, or `null`. Satisfies `getKind`. */
|
|
86
|
+
getKind(artifactId: string): Promise<UploadKind | null>;
|
|
87
|
+
/** Satisfies the optional `PulseVaultStorage.getRelatedTo` contract. */
|
|
88
|
+
getRelatedTo(artifactId: string): Promise<string | null>;
|
|
89
|
+
/** Satisfies the optional `PulseVaultStorage.getChecksum` contract. */
|
|
90
|
+
getChecksum(artifactId: string): Promise<string | null>;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Build an S3/R2-backed storage adapter.
|
|
94
|
+
*
|
|
95
|
+
* Async because it lazily imports the optional `@aws-sdk/*` and
|
|
96
|
+
* `@tus/s3-store` packages — `await` it before registering the plugin:
|
|
97
|
+
*
|
|
98
|
+
* ```ts
|
|
99
|
+
* const storage = await createS3Storage({
|
|
100
|
+
* bucket: "pulse-videos",
|
|
101
|
+
* endpoint: `https://${ACCOUNT}.r2.cloudflarestorage.com`,
|
|
102
|
+
* accessKeyId: process.env.R2_ACCESS_KEY,
|
|
103
|
+
* secretAccessKey: process.env.R2_SECRET_KEY,
|
|
104
|
+
* });
|
|
105
|
+
* await app.register(pulseVault, { storage, prefix: "/pulsevault", maxUploadSize: Infinity });
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export declare function createS3Storage(opts: S3StorageOptions): Promise<S3Storage>;
|
|
109
|
+
//# sourceMappingURL=s3.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../src/storage/s3.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAY,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAEV,iBAAiB,EAEjB,UAAU,EACX,MAAM,YAAY,CAAC;AA8EpB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,2EAA2E;IAC3E,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;CACxC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,iBAAiB,GAAG;IAC1C,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAClE;;;;;OAKG;IACH,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACpD;;;;;;OAMG;IACH,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5F,4EAA4E;IAC5E,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACxD,wEAAwE;IACxE,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzD,uEAAuE;IACvE,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACzD,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,CAAC,CAoVhF"}
|