@mieweb/pulsevault 0.0.1 → 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 -14
- package/dist/routes/pulsevault.d.ts.map +1 -1
- package/dist/routes/pulsevault.js +127 -247
- 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
|
@@ -1,30 +1,34 @@
|
|
|
1
|
-
import type { FastifyPluginAsync, FastifyPluginOptions
|
|
2
|
-
import type { PulseVaultCacheOptions } from
|
|
3
|
-
import {
|
|
4
|
-
import type {
|
|
5
|
-
import type {
|
|
6
|
-
|
|
1
|
+
import type { FastifyPluginAsync, FastifyPluginOptions } from 'fastify';
|
|
2
|
+
import type { PulseVaultCacheOptions } from '../app.js';
|
|
3
|
+
import { PROTOCOL_VERSION } from '../core.js';
|
|
4
|
+
import type { PulseVaultOnUploadComplete, PulseVaultOnArtifactEvent } from '../lib/pulsevaultTus.js';
|
|
5
|
+
import type { PulseVaultValidatePayload } from '../lib/magic.js';
|
|
6
|
+
import { type PulseVaultAuthorize } from '../lib/authorize.js';
|
|
7
|
+
import type { PulseVaultAllowedExtensions } from '../lib/options.js';
|
|
8
|
+
import type { PulseVaultStorage, UploadKind } from '../storage/types.js';
|
|
9
|
+
export type { PulseVaultAuthorize, PulseVaultAuthorizeContext, PulseVaultAuthorizePhase, } from '../lib/authorize.js';
|
|
10
|
+
declare module 'fastify' {
|
|
7
11
|
interface FastifyRequest {
|
|
8
12
|
pulseVault?: {
|
|
9
|
-
|
|
13
|
+
artifactId: string;
|
|
14
|
+
kind: UploadKind;
|
|
15
|
+
relatedTo?: string;
|
|
10
16
|
};
|
|
11
17
|
}
|
|
12
18
|
}
|
|
13
|
-
export type PulseVaultAuthorizePhase = "create" | "patch" | "resolve" | "delete";
|
|
14
|
-
export type PulseVaultAuthorizeContext = {
|
|
15
|
-
phase: PulseVaultAuthorizePhase;
|
|
16
|
-
videoid: string;
|
|
17
|
-
};
|
|
18
|
-
export type PulseVaultAuthorize = (request: FastifyRequest, ctx: PulseVaultAuthorizeContext) => void | Promise<void>;
|
|
19
19
|
export type PulseVaultRoutesOptions = {
|
|
20
20
|
storage: PulseVaultStorage;
|
|
21
21
|
maxUploadSize: number;
|
|
22
|
-
allowedExtensions:
|
|
22
|
+
allowedExtensions: PulseVaultAllowedExtensions;
|
|
23
|
+
/** Advertised via `GET /capabilities` so the client knows which upload strategy this server expects. */
|
|
24
|
+
uploadUnit: 'beat' | 'merged';
|
|
23
25
|
cache?: PulseVaultCacheOptions;
|
|
24
26
|
authorize?: PulseVaultAuthorize;
|
|
25
27
|
validatePayload?: PulseVaultValidatePayload;
|
|
26
28
|
onUploadComplete?: PulseVaultOnUploadComplete;
|
|
29
|
+
onArtifactEvent?: PulseVaultOnArtifactEvent;
|
|
27
30
|
} & FastifyPluginOptions;
|
|
28
31
|
declare const pulseVaultRoutes: FastifyPluginAsync<PulseVaultRoutesOptions>;
|
|
29
32
|
export default pulseVaultRoutes;
|
|
33
|
+
export { PROTOCOL_VERSION };
|
|
30
34
|
//# sourceMappingURL=pulsevault.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pulsevault.d.ts","sourceRoot":"","sources":["../../src/routes/pulsevault.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"pulsevault.d.ts","sourceRoot":"","sources":["../../src/routes/pulsevault.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,EAIrB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,EAAwB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,KAAK,EACV,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEzE,YAAY,EACV,mBAAmB,EACnB,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAK7B,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,cAAc;QACtB,UAAU,CAAC,EAAE;YAAE,UAAU,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,UAAU,CAAC;YAAC,SAAS,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;KAC3E;CACF;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,2BAA2B,CAAC;IAC/C,wGAAwG;IACxG,UAAU,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC9B,KAAK,CAAC,EAAE,sBAAsB,CAAC;IAC/B,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,eAAe,CAAC,EAAE,yBAAyB,CAAC;IAC5C,gBAAgB,CAAC,EAAE,0BAA0B,CAAC;IAC9C,eAAe,CAAC,EAAE,yBAAyB,CAAC;CAC7C,GAAG,oBAAoB,CAAC;AA4JzB,QAAA,MAAM,gBAAgB,EAAE,kBAAkB,CAAC,uBAAuB,CA8EjE,CAAC;AAEF,eAAe,gBAAgB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -1,315 +1,195 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { pulseVaultError } from "../lib/errors.js";
|
|
4
|
-
import { isUuid } from "../lib/uuid.js";
|
|
5
|
-
/**
|
|
6
|
-
* Pull `videoid` out of a raw `Upload-Metadata` header. Format is a
|
|
7
|
-
* comma-separated list of `<key> <base64-value>` pairs (tus v1 creation
|
|
8
|
-
* extension). We only care about `videoid`; everything else is left to the
|
|
9
|
-
* tus server proper.
|
|
10
|
-
*/
|
|
11
|
-
function parseVideoidFromMetadata(header) {
|
|
12
|
-
for (const pair of header.split(",")) {
|
|
13
|
-
const trimmed = pair.trim();
|
|
14
|
-
if (!trimmed)
|
|
15
|
-
continue;
|
|
16
|
-
const sep = trimmed.indexOf(" ");
|
|
17
|
-
if (sep < 0)
|
|
18
|
-
continue;
|
|
19
|
-
const key = trimmed.slice(0, sep);
|
|
20
|
-
if (key !== "videoid")
|
|
21
|
-
continue;
|
|
22
|
-
const value = trimmed.slice(sep + 1).trim();
|
|
23
|
-
if (!value)
|
|
24
|
-
return undefined;
|
|
25
|
-
try {
|
|
26
|
-
const decoded = Buffer.from(value, "base64").toString("utf8");
|
|
27
|
-
return isUuid(decoded) ? decoded : undefined;
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
return undefined;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return undefined;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Decode the last URL segment of a tus PATCH/HEAD/DELETE (base64url-encoded
|
|
37
|
-
* id) and extract the first path component, which the plugin always shapes as
|
|
38
|
-
* the videoid (see `pulseVaultTus.ts`).
|
|
39
|
-
*/
|
|
40
|
-
function videoidFromTusUrl(url) {
|
|
41
|
-
const match = url.match(/\/upload\/([^/?#]+)/);
|
|
42
|
-
if (!match?.[1])
|
|
43
|
-
return undefined;
|
|
44
|
-
let decoded;
|
|
45
|
-
try {
|
|
46
|
-
decoded = Buffer.from(match[1], "base64url").toString("utf8");
|
|
47
|
-
}
|
|
48
|
-
catch {
|
|
49
|
-
return undefined;
|
|
50
|
-
}
|
|
51
|
-
const first = decoded.split("/", 1)[0];
|
|
52
|
-
return isUuid(first) ? first : undefined;
|
|
53
|
-
}
|
|
54
|
-
function extractAuthzStatus(err) {
|
|
55
|
-
const e = err;
|
|
56
|
-
if (typeof e?.statusCode === "number")
|
|
57
|
-
return e.statusCode;
|
|
58
|
-
if (typeof e?.status_code === "number")
|
|
59
|
-
return e.status_code;
|
|
60
|
-
return 403;
|
|
61
|
-
}
|
|
62
|
-
function extractAuthzMessage(err) {
|
|
63
|
-
if (err instanceof Error && err.message)
|
|
64
|
-
return err.message;
|
|
65
|
-
return "Forbidden";
|
|
66
|
-
}
|
|
1
|
+
import { createPulseVaultCore, PROTOCOL_VERSION } from '../core.js';
|
|
2
|
+
import {} from '../lib/authorize.js';
|
|
67
3
|
const pulseVaultErrorResponse = {
|
|
68
|
-
type:
|
|
4
|
+
type: 'object',
|
|
69
5
|
properties: {
|
|
70
|
-
ok: { type:
|
|
71
|
-
error: { type:
|
|
6
|
+
ok: { type: 'boolean' },
|
|
7
|
+
error: { type: 'string' },
|
|
72
8
|
},
|
|
73
|
-
required: [
|
|
9
|
+
required: ['ok', 'error'],
|
|
74
10
|
};
|
|
75
11
|
const tusRouteSchema = {
|
|
76
|
-
tags: [
|
|
77
|
-
summary:
|
|
78
|
-
description:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
"- `
|
|
82
|
-
|
|
83
|
-
"
|
|
12
|
+
tags: ['pulsevault'],
|
|
13
|
+
summary: 'TUS resumable upload endpoint',
|
|
14
|
+
description: 'TUS v1 resumable upload protocol.\n\n' +
|
|
15
|
+
'- `POST` creates a new upload. The `Upload-Metadata` header must include base64-encoded key/value pairs:\n' +
|
|
16
|
+
' - `artifactId` (or the legacy `videoid`/`projectid` aliases) — a UUID generated by your server.\n' +
|
|
17
|
+
" - `filename` — original filename; the extension must match the kind's allowed list.\n" +
|
|
18
|
+
' - `kind` — `video` (default), `project`, or `captions`. Determines the storage subdir and which completion hooks fire.\n' +
|
|
19
|
+
" - `relatedTo` — optional UUID of another artifact this one belongs to (e.g. a video's captions, or a beat belonging to a pulse manifest's session).\n" +
|
|
20
|
+
' - `checksum` — optional `<algorithm>:<hex digest>` of the finished file, verified post-upload if a checksum validator is configured.\n' +
|
|
21
|
+
'- `PATCH` appends a chunk at the offset given by `Upload-Offset`, with `Content-Type: application/offset+octet-stream`.\n' +
|
|
22
|
+
'- `HEAD` returns the current offset for a resumable upload.\n' +
|
|
23
|
+
'- `DELETE` cancels an in-flight upload.\n\n' +
|
|
24
|
+
'See https://tus.io/protocols/resumable-upload for the full protocol.',
|
|
84
25
|
response: {
|
|
85
|
-
400: { description:
|
|
26
|
+
400: { description: 'Invalid request.', ...pulseVaultErrorResponse },
|
|
86
27
|
403: {
|
|
87
|
-
description:
|
|
28
|
+
description: 'Authorize hook rejected the request.',
|
|
88
29
|
...pulseVaultErrorResponse,
|
|
89
30
|
},
|
|
90
31
|
},
|
|
91
32
|
};
|
|
92
|
-
const
|
|
93
|
-
tags: [
|
|
94
|
-
summary:
|
|
95
|
-
description:
|
|
33
|
+
const artifactDeleteSchema = {
|
|
34
|
+
tags: ['pulsevault'],
|
|
35
|
+
summary: 'Delete an uploaded artifact',
|
|
36
|
+
description: 'Deletes all storage for an artifactId (bytes + sidecar metadata), regardless of kind. Runs the `authorize` hook with `phase: "delete"` before the adapter\'s `remove` is called. Returns 204 on success, 404 if the artifactId was unknown, 501 if the adapter does not implement `remove`.',
|
|
96
37
|
params: {
|
|
97
|
-
type:
|
|
38
|
+
type: 'object',
|
|
98
39
|
properties: {
|
|
99
|
-
|
|
100
|
-
type:
|
|
101
|
-
format:
|
|
102
|
-
description:
|
|
40
|
+
artifactId: {
|
|
41
|
+
type: 'string',
|
|
42
|
+
format: 'uuid',
|
|
43
|
+
description: 'UUID of the upload to delete.',
|
|
103
44
|
},
|
|
104
45
|
},
|
|
105
|
-
required: [
|
|
46
|
+
required: ['artifactId'],
|
|
106
47
|
},
|
|
107
48
|
response: {
|
|
108
49
|
400: {
|
|
109
|
-
description:
|
|
50
|
+
description: '`artifactId` is not a valid UUID.',
|
|
110
51
|
...pulseVaultErrorResponse,
|
|
111
52
|
},
|
|
112
53
|
403: {
|
|
113
|
-
description:
|
|
54
|
+
description: 'Authorize hook rejected the request.',
|
|
114
55
|
...pulseVaultErrorResponse,
|
|
115
56
|
},
|
|
116
|
-
404: { description:
|
|
57
|
+
404: { description: 'Artifact not found.', ...pulseVaultErrorResponse },
|
|
117
58
|
501: {
|
|
118
|
-
description:
|
|
59
|
+
description: 'Storage adapter does not implement delete.',
|
|
119
60
|
...pulseVaultErrorResponse,
|
|
120
61
|
},
|
|
121
62
|
},
|
|
122
63
|
};
|
|
123
|
-
const
|
|
124
|
-
tags: [
|
|
125
|
-
summary:
|
|
126
|
-
description: "Resolves the `
|
|
64
|
+
const artifactGetSchema = {
|
|
65
|
+
tags: ['pulsevault'],
|
|
66
|
+
summary: 'Serve a previously uploaded artifact',
|
|
67
|
+
description: "Resolves the `artifactId` through the configured storage adapter and either streams the bytes or redirects (for CDN-backed adapters). The artifact's kind (video, project, or captions) is resolved from storage, not the URL. Runs the `authorize` hook before resolve.",
|
|
127
68
|
params: {
|
|
128
|
-
type:
|
|
69
|
+
type: 'object',
|
|
70
|
+
properties: {
|
|
71
|
+
artifactId: {
|
|
72
|
+
type: 'string',
|
|
73
|
+
format: 'uuid',
|
|
74
|
+
description: 'UUID returned from the upload flow.',
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
required: ['artifactId'],
|
|
78
|
+
},
|
|
79
|
+
querystring: {
|
|
80
|
+
type: 'object',
|
|
129
81
|
properties: {
|
|
130
|
-
|
|
131
|
-
type:
|
|
132
|
-
|
|
133
|
-
description: "UUID returned from the reserve/TUS-create flow.",
|
|
82
|
+
token: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: 'Optional bearer token for pre-authenticated watch links. Forwarded to the `authorize` hook as `ctx.token` so parent servers can validate it without a separate login step.',
|
|
134
85
|
},
|
|
135
86
|
},
|
|
136
|
-
required: ["videoid"],
|
|
137
87
|
},
|
|
138
88
|
response: {
|
|
139
89
|
400: {
|
|
140
|
-
description:
|
|
90
|
+
description: '`artifactId` is not a valid UUID.',
|
|
141
91
|
...pulseVaultErrorResponse,
|
|
142
92
|
},
|
|
143
93
|
403: {
|
|
144
|
-
description:
|
|
94
|
+
description: 'Authorize hook rejected the request.',
|
|
145
95
|
...pulseVaultErrorResponse,
|
|
146
96
|
},
|
|
147
|
-
404: { description:
|
|
97
|
+
404: { description: 'Artifact not found.', ...pulseVaultErrorResponse },
|
|
148
98
|
},
|
|
149
99
|
};
|
|
100
|
+
const capabilitiesSchema = {
|
|
101
|
+
tags: ['pulsevault'],
|
|
102
|
+
summary: "Discover this deployment's protocol version and configuration",
|
|
103
|
+
description: 'Unauthenticated — the response carries no secrets. Lets a client detect protocol compatibility before pairing, and which upload strategy (`uploadUnit`) this server expects.',
|
|
104
|
+
response: {
|
|
105
|
+
200: {
|
|
106
|
+
type: 'object',
|
|
107
|
+
properties: {
|
|
108
|
+
protocolVersion: { type: 'number' },
|
|
109
|
+
minSupportedVersion: { type: 'number' },
|
|
110
|
+
maxSupportedVersion: { type: 'number' },
|
|
111
|
+
uploadUnit: { type: 'string', enum: ['beat', 'merged'] },
|
|
112
|
+
kinds: { type: 'array', items: { type: 'string' } },
|
|
113
|
+
allowedExtensions: {
|
|
114
|
+
type: 'object',
|
|
115
|
+
properties: {
|
|
116
|
+
video: { type: 'array', items: { type: 'string' } },
|
|
117
|
+
project: { type: 'array', items: { type: 'string' } },
|
|
118
|
+
captions: { type: 'array', items: { type: 'string' } },
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
maxUploadSize: { type: 'number' },
|
|
122
|
+
checksum: {
|
|
123
|
+
type: 'object',
|
|
124
|
+
properties: { algorithms: { type: 'array', items: { type: 'string' } } },
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
/** Coerce the raw route param to a string; an invalid UUID is rejected by the core's own check either way. */
|
|
131
|
+
function paramToString(value) {
|
|
132
|
+
return typeof value === 'string' ? value : '';
|
|
133
|
+
}
|
|
150
134
|
const pulseVaultRoutes = async (fastify, opts) => {
|
|
151
|
-
const { storage, maxUploadSize, allowedExtensions, cache, authorize, validatePayload, onUploadComplete, } = opts;
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
|
|
135
|
+
const { storage, maxUploadSize, allowedExtensions, uploadUnit, cache, authorize, validatePayload, onUploadComplete, onArtifactEvent, } = opts;
|
|
136
|
+
// All hook orchestration, tus glue, and artifact GET/DELETE logic lives in
|
|
137
|
+
// the framework-agnostic core (`../core.js`); this file only wires Fastify's
|
|
138
|
+
// routing/schema/lifecycle around it, so behavior can't drift from the
|
|
139
|
+
// `./core` entry point non-Fastify hosts use.
|
|
140
|
+
const core = createPulseVaultCore({
|
|
155
141
|
storage,
|
|
156
|
-
|
|
157
|
-
|
|
142
|
+
// `fastify.prefix` is `""` when the plugin is mounted at the root.
|
|
143
|
+
basePath: fastify.prefix,
|
|
144
|
+
maxUploadSize,
|
|
145
|
+
uploadUnit,
|
|
158
146
|
allowedExtensions,
|
|
147
|
+
cache,
|
|
148
|
+
authorize,
|
|
159
149
|
validatePayload,
|
|
160
150
|
onUploadComplete,
|
|
151
|
+
onArtifactEvent,
|
|
152
|
+
logger: fastify.log,
|
|
161
153
|
});
|
|
162
|
-
fastify.addContentTypeParser(
|
|
154
|
+
fastify.addContentTypeParser('application/offset+octet-stream', (_request, _payload, done) => {
|
|
163
155
|
done(null);
|
|
164
156
|
});
|
|
165
|
-
|
|
166
|
-
* Run the consumer's `authorize` hook (if any) for a TUS request. Returns
|
|
167
|
-
* `true` iff the request may proceed; on rejection, this function already
|
|
168
|
-
* wrote the response.
|
|
169
|
-
*/
|
|
170
|
-
const runAuthorize = async (request, reply, phase) => {
|
|
171
|
-
let videoid;
|
|
172
|
-
if (phase === "create") {
|
|
173
|
-
const meta = request.headers["upload-metadata"];
|
|
174
|
-
if (typeof meta === "string") {
|
|
175
|
-
videoid = parseVideoidFromMetadata(meta);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
else {
|
|
179
|
-
videoid = videoidFromTusUrl(request.url);
|
|
180
|
-
}
|
|
181
|
-
if (videoid) {
|
|
182
|
-
request.pulseVault = { videoid };
|
|
183
|
-
}
|
|
184
|
-
if (!authorize) {
|
|
185
|
-
return { ok: true, videoid };
|
|
186
|
-
}
|
|
187
|
-
// If we can't extract a videoid, let tus produce its own 4xx for malformed
|
|
188
|
-
// input rather than synthesize a fake authorize failure.
|
|
189
|
-
if (!videoid) {
|
|
190
|
-
return { ok: true, videoid };
|
|
191
|
-
}
|
|
192
|
-
try {
|
|
193
|
-
await authorize(request, { phase, videoid });
|
|
194
|
-
return { ok: true, videoid };
|
|
195
|
-
}
|
|
196
|
-
catch (err) {
|
|
197
|
-
const statusCode = extractAuthzStatus(err);
|
|
198
|
-
const message = extractAuthzMessage(err);
|
|
199
|
-
request.log.info({ err, videoid, phase, statusCode }, "pulsevault authorize rejected");
|
|
200
|
-
await reply.code(statusCode).send(pulseVaultError(message));
|
|
201
|
-
return { ok: false };
|
|
202
|
-
}
|
|
203
|
-
};
|
|
157
|
+
const tusMethods = ['POST', 'PATCH', 'HEAD', 'DELETE', 'OPTIONS'];
|
|
204
158
|
const tusHandler = async (request, reply) => {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
return;
|
|
209
|
-
// Once hijacked, Fastify will not write to this reply on our behalf, so we
|
|
210
|
-
// must translate any unexpected throw from `@tus/server` into a response
|
|
211
|
-
// ourselves — otherwise the socket stays open until the client times out.
|
|
159
|
+
// The core writes directly to the raw response (tus dispatch, authorize
|
|
160
|
+
// rejections, error translation) — hijack so Fastify doesn't also try to
|
|
161
|
+
// manage this reply afterward.
|
|
212
162
|
reply.hijack();
|
|
213
|
-
|
|
214
|
-
await pulseVaultTusContext.run({ request, videoid: authz.videoid }, () => tusServer.handle(request.raw, reply.raw));
|
|
215
|
-
}
|
|
216
|
-
catch (err) {
|
|
217
|
-
request.log.error({ err }, "pulsevault tus handler failed");
|
|
218
|
-
if (reply.raw.headersSent || reply.raw.writableEnded) {
|
|
219
|
-
reply.raw.destroy();
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
reply.raw.statusCode = 500;
|
|
223
|
-
reply.raw.setHeader("content-type", "text/plain; charset=utf-8");
|
|
224
|
-
reply.raw.end("Internal Server Error");
|
|
225
|
-
}
|
|
163
|
+
await core.handleTus(request.raw, reply.raw);
|
|
226
164
|
};
|
|
227
|
-
const tusMethods = ["POST", "PATCH", "HEAD", "DELETE", "OPTIONS"];
|
|
228
165
|
fastify.route({
|
|
229
166
|
method: [...tusMethods],
|
|
230
|
-
url:
|
|
167
|
+
url: '/upload',
|
|
231
168
|
schema: tusRouteSchema,
|
|
232
169
|
handler: tusHandler,
|
|
233
170
|
});
|
|
234
171
|
fastify.route({
|
|
235
172
|
method: [...tusMethods],
|
|
236
|
-
url:
|
|
173
|
+
url: '/upload/*',
|
|
237
174
|
schema: tusRouteSchema,
|
|
238
175
|
handler: tusHandler,
|
|
239
176
|
});
|
|
240
|
-
fastify.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
request.
|
|
248
|
-
if (authorize) {
|
|
249
|
-
try {
|
|
250
|
-
await authorize(request, { phase: "delete", videoid });
|
|
251
|
-
}
|
|
252
|
-
catch (err) {
|
|
253
|
-
const statusCode = extractAuthzStatus(err);
|
|
254
|
-
const message = extractAuthzMessage(err);
|
|
255
|
-
request.log.info({ err, videoid, phase: "delete", statusCode }, "pulsevault authorize rejected");
|
|
256
|
-
return reply.code(statusCode).send(pulseVaultError(message));
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
if (typeof storage.remove !== "function") {
|
|
260
|
-
return reply
|
|
261
|
-
.code(501)
|
|
262
|
-
.send(pulseVaultError("Storage adapter does not support delete"));
|
|
263
|
-
}
|
|
264
|
-
const removed = await storage.remove(videoid);
|
|
265
|
-
if (!removed) {
|
|
266
|
-
return reply.code(404).send(pulseVaultError("Video not found"));
|
|
267
|
-
}
|
|
268
|
-
return reply.code(204).send();
|
|
177
|
+
fastify.get('/capabilities', { schema: capabilitiesSchema }, async (request, reply) => {
|
|
178
|
+
reply.hijack();
|
|
179
|
+
await core.handleCapabilities(request.raw, reply.raw);
|
|
180
|
+
});
|
|
181
|
+
fastify.delete('/artifacts/:artifactId', { schema: artifactDeleteSchema }, async (request, reply) => {
|
|
182
|
+
const artifactId = paramToString(request.params?.artifactId);
|
|
183
|
+
reply.hijack();
|
|
184
|
+
await core.handleArtifactDelete(request.raw, reply.raw, artifactId);
|
|
269
185
|
});
|
|
270
|
-
fastify.get(
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
.send(pulseVaultError("`videoid` must be a valid UUID"));
|
|
276
|
-
}
|
|
277
|
-
request.pulseVault = { videoid };
|
|
278
|
-
// Run authorize *before* resolve so consumers can reject without the
|
|
279
|
-
// response leaking "this videoid exists but you don't own it" vs. "no such
|
|
280
|
-
// videoid".
|
|
281
|
-
if (authorize) {
|
|
282
|
-
try {
|
|
283
|
-
await authorize(request, { phase: "resolve", videoid });
|
|
284
|
-
}
|
|
285
|
-
catch (err) {
|
|
286
|
-
const statusCode = extractAuthzStatus(err);
|
|
287
|
-
const message = extractAuthzMessage(err);
|
|
288
|
-
request.log.info({ err, videoid, phase: "resolve", statusCode }, "pulsevault authorize rejected");
|
|
289
|
-
return reply.code(statusCode).send(pulseVaultError(message));
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
const resolved = await storage.resolve(videoid);
|
|
293
|
-
if (!resolved) {
|
|
294
|
-
return reply.code(404).send(pulseVaultError("Video not found"));
|
|
295
|
-
}
|
|
296
|
-
if (resolved.kind === "redirect") {
|
|
297
|
-
return reply.redirect(resolved.url, resolved.statusCode ?? 302);
|
|
298
|
-
}
|
|
299
|
-
const result = await send(request.raw, resolved.filename, {
|
|
300
|
-
root: resolved.root,
|
|
301
|
-
...cache,
|
|
302
|
-
});
|
|
303
|
-
if (result.type === "error") {
|
|
304
|
-
return reply
|
|
305
|
-
.code(result.statusCode)
|
|
306
|
-
.send(pulseVaultError(result.metadata.error.message));
|
|
307
|
-
}
|
|
308
|
-
for (const [name, value] of Object.entries(result.headers)) {
|
|
309
|
-
reply.header(name, value);
|
|
310
|
-
}
|
|
311
|
-
return reply.code(result.statusCode).send(result.stream);
|
|
186
|
+
fastify.get('/artifacts/:artifactId', { schema: artifactGetSchema }, async (request, reply) => {
|
|
187
|
+
const artifactId = paramToString(request.params?.artifactId);
|
|
188
|
+
const token = request.query?.token;
|
|
189
|
+
reply.hijack();
|
|
190
|
+
await core.handleArtifactGet(request.raw, reply.raw, artifactId, token);
|
|
312
191
|
});
|
|
313
192
|
};
|
|
314
193
|
export default pulseVaultRoutes;
|
|
194
|
+
export { PROTOCOL_VERSION };
|
|
315
195
|
//# sourceMappingURL=pulsevault.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pulsevault.js","sourceRoot":"","sources":["../../src/routes/pulsevault.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pulsevault.js","sourceRoot":"","sources":["../../src/routes/pulsevault.ts"],"names":[],"mappings":"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"}
|
package/dist/storage/local.d.ts
CHANGED
|
@@ -1,34 +1,55 @@
|
|
|
1
|
-
import type { PulseVaultStorage } from
|
|
1
|
+
import type { PulseVaultStorage, UploadKind } from './types.js';
|
|
2
2
|
export type LocalStorageOptions = {
|
|
3
|
-
/** Directory where
|
|
3
|
+
/** Directory where uploads are stored (flat kind-scoped subdirs). Resolved against CWD if relative. */
|
|
4
4
|
workspaceDir: string;
|
|
5
|
+
/**
|
|
6
|
+
* Max number of entries kept in the in-memory metadata cache before the
|
|
7
|
+
* oldest (by insertion order) is evicted. A cache miss falls back to
|
|
8
|
+
* reading the sidecar from disk, so eviction only costs an extra read, not
|
|
9
|
+
* correctness. Defaults to 10,000.
|
|
10
|
+
*/
|
|
11
|
+
metaCacheLimit?: number;
|
|
5
12
|
};
|
|
6
13
|
/**
|
|
7
14
|
* Local adapter storage. Layout contract (stable; downstream tools may rely
|
|
8
15
|
* on it):
|
|
9
16
|
*
|
|
10
17
|
* ```text
|
|
11
|
-
* <workspaceRoot
|
|
12
|
-
* .pulsevault
|
|
13
|
-
* video/<
|
|
14
|
-
* video/<
|
|
18
|
+
* <workspaceRoot>/
|
|
19
|
+
* .pulsevault/<artifactId>.json # sidecar: { version, ext, filename, status, kind, relatedTo }
|
|
20
|
+
* video/<artifactId><ext> # finalized video bytes
|
|
21
|
+
* video/<artifactId><ext>.json # @tus/file-store offset/metadata sidecar
|
|
22
|
+
* project/<artifactId><ext> # finalized project bytes
|
|
23
|
+
* project/<artifactId><ext>.json # @tus/file-store offset/metadata sidecar
|
|
24
|
+
* captions/<artifactId><ext> # finalized captions bytes
|
|
25
|
+
* captions/<artifactId><ext>.json # @tus/file-store offset/metadata sidecar
|
|
15
26
|
* ```
|
|
16
27
|
*
|
|
17
28
|
* `workspaceRoot` is exposed so consumers can layer post-processing (e.g.
|
|
18
29
|
* hydrate an ArtiPod with `video/`, `transcripts/`, `frames/` mounts) against
|
|
19
30
|
* the same on-disk tree from an `onUploadComplete` hook. `getLocalPath` is
|
|
20
31
|
* exposed for `validatePayload` helpers that need to sniff the bytes before
|
|
21
|
-
* the
|
|
32
|
+
* the upload is marked ready.
|
|
22
33
|
*/
|
|
23
34
|
export type LocalStorage = PulseVaultStorage & {
|
|
24
35
|
readonly workspaceRoot: string;
|
|
25
36
|
/**
|
|
26
|
-
* Return the absolute path to the upload bytes for `
|
|
37
|
+
* Return the absolute path to the upload bytes for `artifactId`, regardless
|
|
27
38
|
* of ready state. Falls back to reading the sidecar if the in-memory cache
|
|
28
39
|
* is cold (so it works even after a server restart mid-upload). Returns
|
|
29
|
-
* `null` if the
|
|
40
|
+
* `null` if the artifactId is unknown.
|
|
41
|
+
*/
|
|
42
|
+
getLocalPath(artifactId: string): Promise<string | null>;
|
|
43
|
+
/**
|
|
44
|
+
* Return the artifact kind for a known artifactId without a full resolve.
|
|
45
|
+
* Returns `null` if the artifactId is unknown. Satisfies the optional
|
|
46
|
+
* `PulseVaultStorage.getKind` contract.
|
|
30
47
|
*/
|
|
31
|
-
|
|
48
|
+
getKind(artifactId: string): Promise<UploadKind | null>;
|
|
49
|
+
/** Satisfies the optional `PulseVaultStorage.getRelatedTo` contract. */
|
|
50
|
+
getRelatedTo(artifactId: string): Promise<string | null>;
|
|
51
|
+
/** Satisfies the optional `PulseVaultStorage.getChecksum` contract. */
|
|
52
|
+
getChecksum(artifactId: string): Promise<string | null>;
|
|
32
53
|
};
|
|
33
54
|
export declare function createLocalStorage(opts: LocalStorageOptions): LocalStorage;
|
|
34
55
|
//# sourceMappingURL=local.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/storage/local.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,iBAAiB,
|
|
1
|
+
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/storage/local.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,iBAAiB,EAEjB,UAAU,EACX,MAAM,YAAY,CAAC;AAwEpB,MAAM,MAAM,mBAAmB,GAAG;IAChC,uGAAuG;IACvG,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,MAAM,YAAY,GAAG,iBAAiB,GAAG;IAC7C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzD;;;;OAIG;IACH,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,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,mBAAmB,GAAG,YAAY,CAuO1E"}
|