@mieweb/pulsevault 0.0.2 → 0.1.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/CHANGELOG.md +184 -0
- package/LICENSE +15 -39
- package/OPERATIONS.md +223 -0
- package/PROTOCOL.md +312 -0
- package/README.md +532 -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 +90 -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 +431 -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 +126 -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 +102 -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/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 +39 -0
- package/dist/lib/options.d.ts.map +1 -0
- package/dist/lib/options.js +103 -0
- package/dist/lib/options.js.map +1 -0
- package/dist/lib/pulsevaultTus.d.ts +52 -26
- package/dist/lib/pulsevaultTus.d.ts.map +1 -1
- package/dist/lib/pulsevaultTus.js +111 -43
- package/dist/lib/pulsevaultTus.js.map +1 -1
- package/dist/lib/request.d.ts +24 -0
- package/dist/lib/request.d.ts.map +1 -0
- package/dist/lib/request.js +16 -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 +120 -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 +166 -82
- 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 +432 -0
- package/dist/storage/s3.js.map +1 -0
- package/dist/storage/types.d.ts +69 -17
- package/dist/storage/types.d.ts.map +1 -1
- package/package.json +35 -7
package/dist/storage/local.js
CHANGED
|
@@ -1,51 +1,101 @@
|
|
|
1
|
-
import { FileStore } from
|
|
2
|
-
import fs from
|
|
3
|
-
import path from
|
|
4
|
-
const SIDECAR_NAME = ".pulsevault.json";
|
|
1
|
+
import { FileStore } from '@tus/file-store';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
5
4
|
const SIDECAR_VERSION = 1;
|
|
5
|
+
/** Hidden directory inside workspaceRoot that holds per-upload sidecar files. */
|
|
6
|
+
const PULSEVAULT_META_DIR = '.pulsevault';
|
|
7
|
+
/** Default cap on the in-memory metadata cache before evicting the oldest entry. */
|
|
8
|
+
const DEFAULT_META_CACHE_LIMIT = 10_000;
|
|
9
|
+
/** Map a file extension to the `Content-Type` the GET route should return. */
|
|
10
|
+
function extToContentType(ext) {
|
|
11
|
+
switch (ext) {
|
|
12
|
+
case '.mp4':
|
|
13
|
+
return 'video/mp4';
|
|
14
|
+
case '.zip':
|
|
15
|
+
return 'application/zip';
|
|
16
|
+
case '.srt':
|
|
17
|
+
return 'application/x-subrip';
|
|
18
|
+
default:
|
|
19
|
+
return 'application/octet-stream';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Project a `Sidecar` into the shape kept in the in-memory cache. */
|
|
23
|
+
function sidecarToCachedMeta(sidecar, ready) {
|
|
24
|
+
return {
|
|
25
|
+
ext: sidecar.ext,
|
|
26
|
+
ready,
|
|
27
|
+
kind: sidecar.kind ?? 'video',
|
|
28
|
+
relatedTo: sidecar.relatedTo,
|
|
29
|
+
checksum: sidecar.checksum,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
6
32
|
export function createLocalStorage(opts) {
|
|
7
33
|
const workspaceRoot = path.resolve(opts.workspaceDir);
|
|
8
34
|
const datastore = new FileStore({ directory: workspaceRoot });
|
|
9
|
-
|
|
10
|
-
//
|
|
11
|
-
//
|
|
35
|
+
const metaCacheLimit = opts.metaCacheLimit ?? DEFAULT_META_CACHE_LIMIT;
|
|
36
|
+
// Metadata cache keyed by artifactId. Populated eagerly on reserve and
|
|
37
|
+
// lazily from the sidecar on cache-miss — so we never do a workspace-wide
|
|
38
|
+
// scan at boot and never do a per-request readdir on the GET hot path.
|
|
39
|
+
// Bounded with simple insertion-order eviction (a `Map` preserves insertion
|
|
40
|
+
// order, and re-setting a key moves it to the end) so a long-running server
|
|
41
|
+
// doesn't grow this unboundedly; a cache miss just costs an extra disk read.
|
|
12
42
|
const metaCache = new Map();
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
43
|
+
const cacheSet = (artifactId, meta) => {
|
|
44
|
+
// Re-inserting moves the key to the end of iteration order, so eviction
|
|
45
|
+
// below always drops the actual least-recently-set entry.
|
|
46
|
+
metaCache.delete(artifactId);
|
|
47
|
+
metaCache.set(artifactId, meta);
|
|
48
|
+
if (metaCache.size > metaCacheLimit) {
|
|
49
|
+
const oldest = metaCache.keys().next().value;
|
|
50
|
+
if (oldest !== undefined)
|
|
51
|
+
metaCache.delete(oldest);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
/** Absolute path to the hidden metadata directory. */
|
|
55
|
+
const sidecarDir = () => path.join(workspaceRoot, PULSEVAULT_META_DIR);
|
|
56
|
+
/** Absolute path to the sidecar JSON for a given artifactId. */
|
|
57
|
+
const sidecarPath = (artifactId) => path.join(sidecarDir(), `${artifactId}.json`);
|
|
58
|
+
/** Relative path (from workspaceRoot) to the artifact bytes. */
|
|
59
|
+
const artifactRelPath = (artifactId, kind, ext) => `${kind}/${artifactId}${ext}`;
|
|
60
|
+
const writeSidecar = async (artifactId, sidecar) => {
|
|
17
61
|
// Atomic tmp + rename so a crash mid-write can never leave a truncated
|
|
18
62
|
// JSON blob that `loadMeta` would then treat as corrupt.
|
|
19
|
-
const finalPath = sidecarPath(
|
|
63
|
+
const finalPath = sidecarPath(artifactId);
|
|
20
64
|
const tmpPath = `${finalPath}.tmp`;
|
|
21
|
-
await fs.
|
|
65
|
+
await fs.mkdir(sidecarDir(), { recursive: true });
|
|
66
|
+
await fs.writeFile(tmpPath, JSON.stringify(sidecar), 'utf8');
|
|
22
67
|
await fs.rename(tmpPath, finalPath);
|
|
23
68
|
};
|
|
24
|
-
const readSidecar = async (
|
|
69
|
+
const readSidecar = async (artifactId) => {
|
|
25
70
|
let raw;
|
|
26
71
|
try {
|
|
27
|
-
raw = await fs.readFile(sidecarPath(
|
|
72
|
+
raw = await fs.readFile(sidecarPath(artifactId), 'utf8');
|
|
28
73
|
}
|
|
29
74
|
catch (err) {
|
|
30
|
-
if (err?.code ===
|
|
75
|
+
if (err?.code === 'ENOENT')
|
|
31
76
|
return null;
|
|
32
77
|
throw err;
|
|
33
78
|
}
|
|
34
79
|
try {
|
|
35
80
|
const parsed = JSON.parse(raw);
|
|
36
|
-
if (typeof parsed.ext !==
|
|
81
|
+
if (typeof parsed.ext !== 'string')
|
|
37
82
|
return null;
|
|
38
|
-
if (typeof parsed.filename !==
|
|
83
|
+
if (typeof parsed.filename !== 'string')
|
|
39
84
|
return null;
|
|
40
85
|
// Older sidecars (pre-status) are treated as ready so an in-place
|
|
41
86
|
// upgrade doesn't hide finalized uploads. New uploads always write a
|
|
42
87
|
// `status` field explicitly.
|
|
43
|
-
const status = parsed.status ===
|
|
88
|
+
const status = parsed.status === 'uploading' ? 'uploading' : 'ready';
|
|
89
|
+
// Older sidecars without `kind` default to `"video"` — no migration.
|
|
90
|
+
const kind = parsed.kind === 'project' ? 'project' : parsed.kind === 'captions' ? 'captions' : 'video';
|
|
44
91
|
return {
|
|
45
92
|
version: SIDECAR_VERSION,
|
|
46
93
|
ext: parsed.ext,
|
|
47
94
|
filename: parsed.filename,
|
|
48
95
|
status,
|
|
96
|
+
kind,
|
|
97
|
+
relatedTo: typeof parsed.relatedTo === 'string' ? parsed.relatedTo : undefined,
|
|
98
|
+
checksum: typeof parsed.checksum === 'string' ? parsed.checksum : undefined,
|
|
49
99
|
};
|
|
50
100
|
}
|
|
51
101
|
catch {
|
|
@@ -54,104 +104,135 @@ export function createLocalStorage(opts) {
|
|
|
54
104
|
return null;
|
|
55
105
|
}
|
|
56
106
|
};
|
|
57
|
-
const loadMeta = async (
|
|
58
|
-
const cached = metaCache.get(
|
|
107
|
+
const loadMeta = async (artifactId) => {
|
|
108
|
+
const cached = metaCache.get(artifactId);
|
|
59
109
|
if (cached)
|
|
60
110
|
return cached;
|
|
61
|
-
const sidecar = await readSidecar(
|
|
111
|
+
const sidecar = await readSidecar(artifactId);
|
|
62
112
|
if (!sidecar)
|
|
63
113
|
return null;
|
|
64
|
-
const meta =
|
|
65
|
-
|
|
66
|
-
ready: sidecar.status === "ready",
|
|
67
|
-
};
|
|
68
|
-
metaCache.set(videoid, meta);
|
|
114
|
+
const meta = sidecarToCachedMeta(sidecar, sidecar.status === 'ready');
|
|
115
|
+
cacheSet(artifactId, meta);
|
|
69
116
|
return meta;
|
|
70
117
|
};
|
|
71
118
|
const initialize = async () => {
|
|
72
|
-
await fs.mkdir(
|
|
119
|
+
await fs.mkdir(sidecarDir(), { recursive: true });
|
|
120
|
+
// @tus/file-store creates `workspaceRoot` with mode 0777 if it doesn't already exist;
|
|
121
|
+
// tighten it so the upload tree isn't world-writable under a permissive umask.
|
|
122
|
+
await fs.chmod(workspaceRoot, 0o750).catch(() => { });
|
|
73
123
|
};
|
|
74
|
-
const reserveUpload = async ({
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// overwrite the file chunk-by-chunk on subsequent PATCHes. Translates
|
|
79
|
-
// to HTTP 409 via @tus/server's error path.
|
|
80
|
-
const meta = await loadMeta(videoid);
|
|
81
|
-
if (meta) {
|
|
82
|
-
throw Object.assign(new Error(`videoid ${videoid} already has an upload`), { statusCode: 409, status_code: 409 });
|
|
83
|
-
}
|
|
84
|
-
const dir = videoDir(videoid);
|
|
85
|
-
await fs.mkdir(path.join(dir, "video"), { recursive: true });
|
|
86
|
-
await writeSidecar(videoid, {
|
|
124
|
+
const reserveUpload = async ({ artifactId, filename, ext, kind, relatedTo, checksum, }) => {
|
|
125
|
+
await fs.mkdir(path.join(workspaceRoot, kind), { recursive: true });
|
|
126
|
+
await fs.mkdir(sidecarDir(), { recursive: true });
|
|
127
|
+
const sidecar = {
|
|
87
128
|
version: SIDECAR_VERSION,
|
|
88
129
|
ext,
|
|
89
130
|
filename,
|
|
90
|
-
status:
|
|
91
|
-
|
|
92
|
-
|
|
131
|
+
status: 'uploading',
|
|
132
|
+
kind,
|
|
133
|
+
relatedTo,
|
|
134
|
+
checksum,
|
|
135
|
+
};
|
|
136
|
+
// Collision guard: `wx` fails atomically with EEXIST if a sidecar already exists for
|
|
137
|
+
// this artifactId, rather than the previous read-then-write (`loadMeta` then
|
|
138
|
+
// `writeSidecar`) which left a window for two concurrent/retried requests to both pass
|
|
139
|
+
// the check before either had written — letting the second silently clobber the first's
|
|
140
|
+
// sidecar and race @tus/file-store's own offset tracking. Translates to HTTP 409 via
|
|
141
|
+
// @tus/server's error path, same as before.
|
|
142
|
+
try {
|
|
143
|
+
await fs.writeFile(sidecarPath(artifactId), JSON.stringify(sidecar), { flag: 'wx' });
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
if (err?.code !== 'EEXIST')
|
|
147
|
+
throw err;
|
|
148
|
+
// A file already exists at this path, but `readSidecar` treats a malformed/corrupt
|
|
149
|
+
// one as absent (e.g. debris from a crash mid-write) — re-check before deciding this
|
|
150
|
+
// is a genuine collision rather than debris that's safe to overwrite.
|
|
151
|
+
const existing = await readSidecar(artifactId);
|
|
152
|
+
if (existing) {
|
|
153
|
+
throw Object.assign(new Error(`artifactId ${artifactId} already has an upload`), {
|
|
154
|
+
statusCode: 409,
|
|
155
|
+
status_code: 409,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
await writeSidecar(artifactId, sidecar);
|
|
159
|
+
}
|
|
160
|
+
cacheSet(artifactId, { ext, ready: false, kind, relatedTo, checksum });
|
|
93
161
|
// @tus/file-store joins this onto its configured `directory`, so the
|
|
94
|
-
// actual file lands at `<workspaceRoot>/<
|
|
95
|
-
return
|
|
162
|
+
// actual file lands at `<workspaceRoot>/<kind>/<artifactId><ext>`.
|
|
163
|
+
return artifactRelPath(artifactId, kind, ext);
|
|
96
164
|
};
|
|
97
|
-
const resolve = async (
|
|
98
|
-
const meta = await loadMeta(
|
|
165
|
+
const resolve = async (artifactId) => {
|
|
166
|
+
const meta = await loadMeta(artifactId);
|
|
99
167
|
// Only serve ready uploads. In-progress uploads stay hidden — a client
|
|
100
168
|
// GETting mid-upload would otherwise receive a truncated file.
|
|
101
169
|
if (!meta || !meta.ready)
|
|
102
170
|
return null;
|
|
103
|
-
const
|
|
104
|
-
const relFile = videoRelPath(videoid, meta.ext);
|
|
171
|
+
const relFile = artifactRelPath(artifactId, meta.kind, meta.ext);
|
|
105
172
|
try {
|
|
106
|
-
const stat = await fs.stat(path.join(
|
|
173
|
+
const stat = await fs.stat(path.join(workspaceRoot, relFile));
|
|
107
174
|
if (!stat.isFile())
|
|
108
175
|
return null;
|
|
109
176
|
}
|
|
110
177
|
catch (err) {
|
|
111
|
-
if (err?.code ===
|
|
178
|
+
if (err?.code === 'ENOENT')
|
|
112
179
|
return null;
|
|
113
180
|
throw err;
|
|
114
181
|
}
|
|
115
|
-
return {
|
|
182
|
+
return {
|
|
183
|
+
kind: 'stream',
|
|
184
|
+
root: workspaceRoot,
|
|
185
|
+
filename: relFile,
|
|
186
|
+
contentType: extToContentType(meta.ext),
|
|
187
|
+
};
|
|
116
188
|
};
|
|
117
|
-
const markReady = async (
|
|
118
|
-
const sidecar = await readSidecar(
|
|
189
|
+
const markReady = async (artifactId) => {
|
|
190
|
+
const sidecar = await readSidecar(artifactId);
|
|
119
191
|
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
|
|
192
|
+
// No sidecar means no `reserveUpload` happened for this artifactId —
|
|
193
|
+
// this is a contract violation by the caller, not a recoverable state.
|
|
194
|
+
throw new Error(`markReady: no sidecar for artifactId ${artifactId} (was reserveUpload called?)`);
|
|
123
195
|
}
|
|
124
|
-
if (sidecar.status ===
|
|
196
|
+
if (sidecar.status === 'ready') {
|
|
125
197
|
// Idempotent: already ready is fine, keep the cache consistent.
|
|
126
|
-
|
|
198
|
+
cacheSet(artifactId, sidecarToCachedMeta(sidecar, true));
|
|
127
199
|
return;
|
|
128
200
|
}
|
|
129
|
-
await writeSidecar(
|
|
130
|
-
|
|
201
|
+
await writeSidecar(artifactId, { ...sidecar, status: 'ready' });
|
|
202
|
+
cacheSet(artifactId, sidecarToCachedMeta(sidecar, true));
|
|
131
203
|
};
|
|
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
|
-
}
|
|
204
|
+
const remove = async (artifactId) => {
|
|
205
|
+
const meta = await loadMeta(artifactId);
|
|
206
|
+
// Drop from cache before rm so a racing `resolve` arriving after the
|
|
207
|
+
// rm but before cache eviction can't hand back a stale path.
|
|
208
|
+
metaCache.delete(artifactId);
|
|
209
|
+
if (!meta)
|
|
210
|
+
return false;
|
|
211
|
+
const artifactPath = path.join(workspaceRoot, meta.kind, `${artifactId}${meta.ext}`);
|
|
212
|
+
await Promise.all([
|
|
213
|
+
fs.rm(artifactPath, { force: true }),
|
|
214
|
+
fs.rm(`${artifactPath}.json`, { force: true }),
|
|
215
|
+
fs.rm(sidecarPath(artifactId), { force: true }),
|
|
216
|
+
]);
|
|
217
|
+
return true;
|
|
149
218
|
};
|
|
150
|
-
const getLocalPath = async (
|
|
151
|
-
const meta = await loadMeta(
|
|
219
|
+
const getLocalPath = async (artifactId) => {
|
|
220
|
+
const meta = await loadMeta(artifactId);
|
|
152
221
|
if (!meta)
|
|
153
222
|
return null;
|
|
154
|
-
return path.join(workspaceRoot,
|
|
223
|
+
return path.join(workspaceRoot, meta.kind, `${artifactId}${meta.ext}`);
|
|
224
|
+
};
|
|
225
|
+
const getKind = async (artifactId) => {
|
|
226
|
+
const meta = await loadMeta(artifactId);
|
|
227
|
+
return meta ? meta.kind : null;
|
|
228
|
+
};
|
|
229
|
+
const getRelatedTo = async (artifactId) => {
|
|
230
|
+
const meta = await loadMeta(artifactId);
|
|
231
|
+
return meta?.relatedTo ?? null;
|
|
232
|
+
};
|
|
233
|
+
const getChecksum = async (artifactId) => {
|
|
234
|
+
const meta = await loadMeta(artifactId);
|
|
235
|
+
return meta?.checksum ?? null;
|
|
155
236
|
};
|
|
156
237
|
return {
|
|
157
238
|
datastore,
|
|
@@ -162,6 +243,9 @@ export function createLocalStorage(opts) {
|
|
|
162
243
|
markReady,
|
|
163
244
|
remove,
|
|
164
245
|
getLocalPath,
|
|
246
|
+
getKind,
|
|
247
|
+
getRelatedTo,
|
|
248
|
+
getChecksum,
|
|
165
249
|
};
|
|
166
250
|
}
|
|
167
251
|
//# 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;AAwEpB,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,CAqVhF"}
|