@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/augment.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./dist/augment.js";
|
package/augment.js
ADDED
package/core.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./dist/core.js";
|
package/core.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Legacy-resolver fallback for the "./core" subpath export. Modern
|
|
2
|
+
// Node/bundlers resolve "@mieweb/pulsevault/core" via package.json's
|
|
3
|
+
// "exports" map straight to dist/core.js and never reach this file — it
|
|
4
|
+
// exists only for resolvers that don't understand "exports" subpath maps
|
|
5
|
+
// (e.g. Meteor's bundler as of Meteor 3.4 / modules@0.20.3), which fall back
|
|
6
|
+
// to plain relative-path resolution and need a real file at this path.
|
|
7
|
+
export * from "./dist/core.js";
|
package/dist/app.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { FastifyPluginAsync } from
|
|
2
|
-
import { type PulseVaultAuthorize } from
|
|
3
|
-
import type { PulseVaultOnUploadComplete } from
|
|
4
|
-
import type { PulseVaultValidatePayload } from
|
|
5
|
-
import type { PulseVaultStorage } from
|
|
1
|
+
import type { FastifyPluginAsync } from 'fastify';
|
|
2
|
+
import { type PulseVaultAuthorize } from './routes/pulsevault.js';
|
|
3
|
+
import type { PulseVaultOnUploadComplete, PulseVaultOnArtifactEvent } from './lib/pulsevaultTus.js';
|
|
4
|
+
import type { PulseVaultValidatePayload } from './lib/magic.js';
|
|
5
|
+
import type { PulseVaultStorage } from './storage/types.js';
|
|
6
6
|
/**
|
|
7
7
|
* Subset of `@fastify/send`'s cache-related options forwarded to the GET
|
|
8
8
|
* route. All upload filenames are content-addressable (keyed by the upload
|
|
@@ -39,6 +39,14 @@ export type PulseVaultPluginOptions = {
|
|
|
39
39
|
* explicit cap for their deployment. Use `Infinity` for no cap.
|
|
40
40
|
*/
|
|
41
41
|
maxUploadSize: number;
|
|
42
|
+
/**
|
|
43
|
+
* Which upload strategy this deployment expects: `"beat"` uploads each
|
|
44
|
+
* clip individually (no client-side merge/re-encode pass) plus a manifest
|
|
45
|
+
* artifact for ordering, while `"merged"` expects one pre-merged video per
|
|
46
|
+
* pulse. Purely advertised via `GET /capabilities` for the client to branch
|
|
47
|
+
* on — `pulsevault` doesn't enforce either. Defaults to `"beat"`.
|
|
48
|
+
*/
|
|
49
|
+
uploadUnit?: 'beat' | 'merged';
|
|
42
50
|
/**
|
|
43
51
|
* Fastify instance decorator name under which the storage adapter is
|
|
44
52
|
* exposed. Defaults to `"pulseVault"`. Override when registering this
|
|
@@ -53,10 +61,21 @@ export type PulseVaultPluginOptions = {
|
|
|
53
61
|
*/
|
|
54
62
|
decoratorName?: string;
|
|
55
63
|
/**
|
|
56
|
-
* File extensions allowed
|
|
57
|
-
*
|
|
64
|
+
* File extensions allowed per artifact kind. Accepts:
|
|
65
|
+
* - A flat array (`[".mp4"]`) — treated as video-only; project/captions
|
|
66
|
+
* default. This is the legacy form for back-compat.
|
|
67
|
+
* - An object with optional `video`/`project`/`captions` keys; unset keys
|
|
68
|
+
* fall back to their defaults.
|
|
69
|
+
* - Omitted entirely — defaults to
|
|
70
|
+
* `{ video: [".mp4"], project: [".pulse", ".zip"], captions: [".srt"] }`.
|
|
71
|
+
*
|
|
72
|
+
* All extensions must include the leading dot and are matched case-insensitively.
|
|
58
73
|
*/
|
|
59
|
-
allowedExtensions?: readonly string[]
|
|
74
|
+
allowedExtensions?: readonly string[] | {
|
|
75
|
+
video?: readonly string[];
|
|
76
|
+
project?: readonly string[];
|
|
77
|
+
captions?: readonly string[];
|
|
78
|
+
};
|
|
60
79
|
/**
|
|
61
80
|
* Cache-control options forwarded to `@fastify/send` for the GET route.
|
|
62
81
|
* When omitted, `@fastify/send`'s defaults apply (`Cache-Control: public,
|
|
@@ -68,47 +87,84 @@ export type PulseVaultPluginOptions = {
|
|
|
68
87
|
* and before `resolve` on GET. Throw to reject the request; a thrown
|
|
69
88
|
* `statusCode`/`status_code` number on the error is honored (default 403).
|
|
70
89
|
*
|
|
71
|
-
* The hook is called with the `FastifyRequest
|
|
72
|
-
*
|
|
73
|
-
*
|
|
90
|
+
* The hook is called with the actual `FastifyRequest` (typed more loosely
|
|
91
|
+
* as `PulseVaultRequest` — the shared shape this option also uses under
|
|
92
|
+
* `@mieweb/pulsevault/core` — since only `.headers` is guaranteed; cast if
|
|
93
|
+
* you need Fastify-specific fields), so consumers can look up sessions,
|
|
94
|
+
* API keys, JWTs, etc. using whatever auth system they have registered
|
|
95
|
+
* higher up in the Fastify tree. Use `createCapabilityAuthorize` (from
|
|
96
|
+
* `./lib/capability-token.js`) for a secure-by-default option that doesn't
|
|
97
|
+
* require writing your own.
|
|
74
98
|
*
|
|
75
99
|
* When omitted, the plugin performs no authorization. For production
|
|
76
100
|
* deployments you almost certainly want to set this — register your auth
|
|
77
101
|
* plugin on the parent scope and let the hook verify ownership of the
|
|
78
|
-
* `
|
|
102
|
+
* `artifactId` before any bytes are written.
|
|
79
103
|
*/
|
|
80
104
|
authorize?: PulseVaultAuthorize;
|
|
81
105
|
/**
|
|
82
|
-
* Optional payload-validation hook
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
106
|
+
* Optional payload-validation hook, called for every artifact kind with
|
|
107
|
+
* `ctx.kind` set accordingly. Runs *after* TUS writes the final byte but
|
|
108
|
+
* *before* the upload is marked ready or `onUploadComplete` fires. Throw to
|
|
109
|
+
* reject — the plugin will call `storage.remove` to free the bytes and
|
|
110
|
+
* return a 4xx (default 422) to the client. The sidecar never flips to
|
|
111
|
+
* `"ready"`, so the artifact is never served.
|
|
87
112
|
*
|
|
88
|
-
* Use this for magic-byte sniffing, virus scanning,
|
|
89
|
-
* needs the final bytes. Ship-ready helpers are exported
|
|
90
|
-
* package — see `createMp4Sniffer`.
|
|
113
|
+
* Use this for magic-byte sniffing, checksum verification, virus scanning,
|
|
114
|
+
* or any check that needs the final bytes. Ship-ready helpers are exported
|
|
115
|
+
* from this package — see `createMp4Sniffer`, `createChecksumValidator`.
|
|
91
116
|
*/
|
|
92
117
|
validatePayload?: PulseVaultValidatePayload;
|
|
93
118
|
/**
|
|
94
|
-
* Optional post-upload hook
|
|
119
|
+
* Optional post-upload hook, fired once TUS writes the final byte *and*
|
|
95
120
|
* any `validatePayload` has passed, and after the adapter's `markReady`
|
|
96
|
-
* has run
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
121
|
+
* has run — for every artifact kind, with `ctx.kind` set accordingly. Use
|
|
122
|
+
* this to flip consumer state (DB row, queue job, audit log). Throwing
|
|
123
|
+
* turns the upload into a 500 response; the artifact is marked ready at
|
|
124
|
+
* this point, so consumers that want all-or-nothing semantics should
|
|
125
|
+
* `storage.remove` before throwing.
|
|
100
126
|
*/
|
|
101
127
|
onUploadComplete?: PulseVaultOnUploadComplete;
|
|
128
|
+
/**
|
|
129
|
+
* Optional low-frequency event hook — fired on authorize rejection (create
|
|
130
|
+
* phase and delete/resolve, never per-chunk patch), upload completion, and
|
|
131
|
+
* payload-validation rejection. One hook covers both ops metrics and a
|
|
132
|
+
* compliance audit trail; see `OPERATIONS.md` for wiring examples.
|
|
133
|
+
*/
|
|
134
|
+
onArtifactEvent?: PulseVaultOnArtifactEvent;
|
|
135
|
+
/**
|
|
136
|
+
* @deprecated Use `validatePayload` instead — it now receives `ctx.kind`
|
|
137
|
+
* and runs for every artifact kind, including `"project"`. Still honored
|
|
138
|
+
* this release (mapped onto `validatePayload` when `kind === "project"`),
|
|
139
|
+
* but will be removed in a future major version. Passing this triggers a
|
|
140
|
+
* one-time `DeprecationWarning` at registration.
|
|
141
|
+
*/
|
|
142
|
+
validateProjectPayload?: PulseVaultValidatePayload;
|
|
143
|
+
/**
|
|
144
|
+
* @deprecated Use `onUploadComplete` instead — it now receives `ctx.kind`
|
|
145
|
+
* and runs for every artifact kind, including `"project"`. Still honored
|
|
146
|
+
* this release (mapped onto `onUploadComplete` when `kind === "project"`),
|
|
147
|
+
* but will be removed in a future major version. Passing this triggers a
|
|
148
|
+
* one-time `DeprecationWarning` at registration.
|
|
149
|
+
*/
|
|
150
|
+
onProjectUploadComplete?: PulseVaultOnUploadComplete;
|
|
102
151
|
};
|
|
103
152
|
declare const _default: FastifyPluginAsync<PulseVaultPluginOptions>;
|
|
104
153
|
export default _default;
|
|
105
|
-
export { createLocalStorage } from
|
|
106
|
-
export type { LocalStorage, LocalStorageOptions } from
|
|
107
|
-
export
|
|
108
|
-
export type {
|
|
109
|
-
export type {
|
|
110
|
-
export {
|
|
111
|
-
export type {
|
|
112
|
-
export {
|
|
113
|
-
export type {
|
|
154
|
+
export { createLocalStorage } from './storage/local.js';
|
|
155
|
+
export type { LocalStorage, LocalStorageOptions } from './storage/local.js';
|
|
156
|
+
export { createS3Storage } from './storage/s3.js';
|
|
157
|
+
export type { S3Storage, S3StorageOptions } from './storage/s3.js';
|
|
158
|
+
export type { PulseVaultResolution, PulseVaultStorage, ReserveUploadParams, UploadKind, } from './storage/types.js';
|
|
159
|
+
export type { PulseVaultAuthorize, PulseVaultAuthorizeContext, PulseVaultAuthorizePhase, } from './routes/pulsevault.js';
|
|
160
|
+
export type { PulseVaultOnUploadComplete, PulseVaultOnArtifactEvent, PulseVaultArtifactEvent, } from './lib/pulsevaultTus.js';
|
|
161
|
+
export { sniffMp4, createMp4Sniffer, createS3Mp4Sniffer } from './lib/magic.js';
|
|
162
|
+
export type { PulseVaultValidatePayload } from './lib/magic.js';
|
|
163
|
+
export { buildUploadLink } from './lib/deeplinks.js';
|
|
164
|
+
export type { UploadLinkOptions } from './lib/deeplinks.js';
|
|
165
|
+
export { issueCapabilityToken, verifyCapabilityToken, createCapabilityAuthorize, } from './lib/capability-token.js';
|
|
166
|
+
export type { CapabilityTokenClaims, IssueCapabilityTokenOptions, VerifyCapabilityTokenOptions, LookupSecret, } from './lib/capability-token.js';
|
|
167
|
+
export { createChecksumValidator, createS3ChecksumValidator, parseChecksumMetadata, } from './lib/checksum.js';
|
|
168
|
+
export type { ChecksumAlgorithm, ParsedChecksum } from './lib/checksum.js';
|
|
169
|
+
export type { PulseVaultRequest, PulseVaultLogger } from './lib/request.js';
|
|
114
170
|
//# sourceMappingURL=app.d.ts.map
|
package/dist/app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD,OAAyB,
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
|
package/dist/app.js
CHANGED
|
@@ -1,54 +1,44 @@
|
|
|
1
|
-
import fp from
|
|
2
|
-
import pulseVaultRoutes, {} from
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const EXTENSION_REGEX = /^\.[^.\s/\\]+$/;
|
|
6
|
-
function validateOptions(opts) {
|
|
7
|
-
if (opts.prefix !== "" && (!opts.prefix.startsWith("/") || opts.prefix.endsWith("/"))) {
|
|
8
|
-
throw new TypeError("`prefix` must be '' or start with '/' with no trailing slash (e.g. '/pulsevault')");
|
|
9
|
-
}
|
|
10
|
-
if (!(opts.maxUploadSize > 0)) {
|
|
11
|
-
throw new TypeError("`maxUploadSize` must be a positive number (use Infinity for no cap)");
|
|
12
|
-
}
|
|
13
|
-
if (opts.allowedExtensions) {
|
|
14
|
-
if (opts.allowedExtensions.length === 0) {
|
|
15
|
-
throw new TypeError("`allowedExtensions` must not be empty");
|
|
16
|
-
}
|
|
17
|
-
for (const ext of opts.allowedExtensions) {
|
|
18
|
-
if (!EXTENSION_REGEX.test(ext)) {
|
|
19
|
-
throw new TypeError(`\`allowedExtensions\` entry ${JSON.stringify(ext)} must start with '.' and contain no nested dots, slashes, or whitespace (e.g. '.mp4')`);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
1
|
+
import fp from 'fastify-plugin';
|
|
2
|
+
import pulseVaultRoutes, {} from './routes/pulsevault.js';
|
|
3
|
+
import { normalizeAllowedExtensions, validateBasePath, validateMaxUploadSize, validateUploadUnit, validateAllowedExtensions, warnIfUsingDeprecatedProjectHooks, composeValidatePayload, composeOnUploadComplete, } from './lib/options.js';
|
|
4
|
+
const DEFAULT_DECORATOR_NAME = 'pulseVault';
|
|
24
5
|
const app = async (fastify, opts) => {
|
|
25
|
-
|
|
6
|
+
validateBasePath(opts.prefix, 'prefix');
|
|
7
|
+
validateMaxUploadSize(opts.maxUploadSize);
|
|
8
|
+
validateUploadUnit(opts.uploadUnit);
|
|
9
|
+
validateAllowedExtensions(opts.allowedExtensions);
|
|
10
|
+
warnIfUsingDeprecatedProjectHooks(opts);
|
|
26
11
|
// Register the shutdown hook *before* awaiting initialize() so any partial
|
|
27
12
|
// state the adapter allocates mid-init still gets cleaned up if Fastify
|
|
28
13
|
// later tears the plugin down.
|
|
29
|
-
fastify.addHook(
|
|
14
|
+
fastify.addHook('onClose', async () => {
|
|
30
15
|
await opts.storage.shutdown?.();
|
|
31
16
|
});
|
|
32
17
|
await opts.storage.initialize?.();
|
|
33
18
|
const decoratorName = opts.decoratorName ?? DEFAULT_DECORATOR_NAME;
|
|
34
|
-
const allowedExtensions = (opts.allowedExtensions
|
|
19
|
+
const allowedExtensions = normalizeAllowedExtensions(opts.allowedExtensions);
|
|
35
20
|
fastify.decorate(decoratorName, opts.storage);
|
|
36
21
|
await fastify.register(pulseVaultRoutes, {
|
|
37
22
|
prefix: opts.prefix,
|
|
38
23
|
storage: opts.storage,
|
|
39
24
|
maxUploadSize: opts.maxUploadSize,
|
|
25
|
+
uploadUnit: opts.uploadUnit ?? 'beat',
|
|
40
26
|
allowedExtensions,
|
|
41
27
|
cache: opts.cache,
|
|
42
28
|
authorize: opts.authorize,
|
|
43
|
-
validatePayload: opts.validatePayload,
|
|
44
|
-
onUploadComplete: opts.onUploadComplete,
|
|
29
|
+
validatePayload: composeValidatePayload(opts.validatePayload, opts.validateProjectPayload),
|
|
30
|
+
onUploadComplete: composeOnUploadComplete(opts.onUploadComplete, opts.onProjectUploadComplete),
|
|
31
|
+
onArtifactEvent: opts.onArtifactEvent,
|
|
45
32
|
});
|
|
46
33
|
};
|
|
47
34
|
export default fp(app, {
|
|
48
|
-
name:
|
|
49
|
-
fastify:
|
|
35
|
+
name: 'pulsevault',
|
|
36
|
+
fastify: '5.x',
|
|
50
37
|
});
|
|
51
|
-
export { createLocalStorage } from
|
|
52
|
-
export {
|
|
53
|
-
export {
|
|
38
|
+
export { createLocalStorage } from './storage/local.js';
|
|
39
|
+
export { createS3Storage } from './storage/s3.js';
|
|
40
|
+
export { sniffMp4, createMp4Sniffer, createS3Mp4Sniffer } from './lib/magic.js';
|
|
41
|
+
export { buildUploadLink } from './lib/deeplinks.js';
|
|
42
|
+
export { issueCapabilityToken, verifyCapabilityToken, createCapabilityAuthorize, } from './lib/capability-token.js';
|
|
43
|
+
export { createChecksumValidator, createS3ChecksumValidator, parseChecksumMetadata, } from './lib/checksum.js';
|
|
54
44
|
//# sourceMappingURL=app.js.map
|
package/dist/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAChC,OAAO,gBAAgB,EAAE,
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAChC,OAAO,gBAAgB,EAAE,EAA4B,MAAM,wBAAwB,CAAC;AAIpF,OAAO,EACL,0BAA0B,EAC1B,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,EAClB,yBAAyB,EACzB,iCAAiC,EACjC,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAoJ1B,MAAM,sBAAsB,GAAG,YAAY,CAAC;AAE5C,MAAM,GAAG,GAAgD,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;IAC/E,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACxC,qBAAqB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC1C,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACpC,yBAAyB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAClD,iCAAiC,CAAC,IAAI,CAAC,CAAC;IAExC,2EAA2E;IAC3E,wEAAwE;IACxE,+BAA+B;IAC/B,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;QACpC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;IAClC,CAAC,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;IAElC,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,sBAAsB,CAAC;IACnE,MAAM,iBAAiB,GAAG,0BAA0B,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAE7E,OAAO,CAAC,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAE9C,MAAM,OAAO,CAAC,QAAQ,CAAC,gBAAgB,EAAE;QACvC,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,MAAM;QACrC,iBAAiB;QACjB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,eAAe,EAAE,sBAAsB,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,sBAAsB,CAAC;QAC1F,gBAAgB,EAAE,uBAAuB,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,uBAAuB,CAAC;QAC9F,eAAe,EAAE,IAAI,CAAC,eAAe;KACtC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,eAAe,EAAE,CAAC,GAAG,EAAE;IACrB,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,KAAK;CACf,CAAC,CAAC;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAkBlD,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEhF,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC;AAOnC,OAAO,EACL,uBAAuB,EACvB,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC"}
|
package/dist/augment.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { PulseVaultStorage } from
|
|
1
|
+
import type { PulseVaultStorage, UploadKind } from './storage/types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Opt-in TypeScript augmentation for the default `pulseVault` decorator and
|
|
4
4
|
* the per-request `request.pulseVault` context that the plugin sets when it
|
|
5
|
-
* recognizes
|
|
6
|
-
* one place in your app when you register the plugin with the default
|
|
5
|
+
* recognizes an artifactId on the incoming request. Import for side effects
|
|
6
|
+
* in one place in your app when you register the plugin with the default
|
|
7
7
|
* `decoratorName`:
|
|
8
8
|
*
|
|
9
9
|
* ```ts
|
|
@@ -19,25 +19,32 @@ import type { PulseVaultStorage } from "./storage/types.js";
|
|
|
19
19
|
* myCustomName: PulseVaultStorage;
|
|
20
20
|
* }
|
|
21
21
|
* interface FastifyRequest {
|
|
22
|
-
* pulseVault?: {
|
|
22
|
+
* pulseVault?: { artifactId: string };
|
|
23
23
|
* }
|
|
24
24
|
* }
|
|
25
25
|
* ```
|
|
26
|
+
*
|
|
27
|
+
* **Breaking change**: this field was named `videoid` before this release.
|
|
28
|
+
* It's renamed to `artifactId` here as a deliberate, separate breaking change
|
|
29
|
+
* from the wire-format rename — update any code reading
|
|
30
|
+
* `request.pulseVault.videoid` to `request.pulseVault.artifactId`.
|
|
26
31
|
*/
|
|
27
|
-
declare module
|
|
32
|
+
declare module 'fastify' {
|
|
28
33
|
interface FastifyInstance {
|
|
29
34
|
pulseVault: PulseVaultStorage;
|
|
30
35
|
}
|
|
31
36
|
interface FastifyRequest {
|
|
32
37
|
/**
|
|
33
|
-
* Populated by the plugin when it can extract
|
|
38
|
+
* Populated by the plugin when it can extract an artifactId from the
|
|
34
39
|
* incoming request (from `Upload-Metadata` on POST, the URL id on
|
|
35
40
|
* PATCH/HEAD/DELETE, or the route param on GET). Present on every
|
|
36
41
|
* request the plugin routes serve that refer to a valid UUID — use it
|
|
37
42
|
* from your own `preHandler` / auth hooks to avoid re-parsing.
|
|
38
43
|
*/
|
|
39
44
|
pulseVault?: {
|
|
40
|
-
|
|
45
|
+
artifactId: string;
|
|
46
|
+
kind: UploadKind;
|
|
47
|
+
relatedTo?: string;
|
|
41
48
|
};
|
|
42
49
|
}
|
|
43
50
|
}
|
package/dist/augment.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"augment.d.ts","sourceRoot":"","sources":["../src/augment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"augment.d.ts","sourceRoot":"","sources":["../src/augment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,eAAe;QACvB,UAAU,EAAE,iBAAiB,CAAC;KAC/B;IACD,UAAU,cAAc;QACtB;;;;;;WAMG;QACH,UAAU,CAAC,EAAE;YAAE,UAAU,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,UAAU,CAAC;YAAC,SAAS,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;KAC3E;CACF;AAED,OAAO,EAAE,CAAC"}
|
package/dist/augment.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"augment.js","sourceRoot":"","sources":["../src/augment.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"augment.js","sourceRoot":"","sources":["../src/augment.ts"],"names":[],"mappings":"AAgDA,OAAO,EAAE,CAAC"}
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import { type PulseVaultOnUploadComplete, type PulseVaultOnArtifactEvent } from './lib/pulsevaultTus.js';
|
|
3
|
+
import type { PulseVaultValidatePayload } from './lib/magic.js';
|
|
4
|
+
import type { PulseVaultAuthorize } from './lib/authorize.js';
|
|
5
|
+
import { type PulseVaultLogger } from './lib/request.js';
|
|
6
|
+
import type { PulseVaultStorage } from './storage/types.js';
|
|
7
|
+
import { type PulseVaultAllowedExtensionsInput } from './lib/options.js';
|
|
8
|
+
/** Wire protocol version this release implements. See `/capabilities` and `PROTOCOL.md`. */
|
|
9
|
+
export declare const PROTOCOL_VERSION = 1;
|
|
10
|
+
export type PulseVaultCoreCacheOptions = {
|
|
11
|
+
cacheControl?: boolean;
|
|
12
|
+
maxAge?: string | number;
|
|
13
|
+
immutable?: boolean;
|
|
14
|
+
};
|
|
15
|
+
export type PulseVaultCoreOptions = {
|
|
16
|
+
/** Storage adapter. Use `createLocalStorage(...)` for filesystem-backed deployments. */
|
|
17
|
+
storage: PulseVaultStorage;
|
|
18
|
+
/**
|
|
19
|
+
* URL path prefix where the core's routes are mounted, e.g. `"/pulsevault"`.
|
|
20
|
+
* Use `""` to mount at the root. Unlike the Fastify plugin, there's no
|
|
21
|
+
* framework-level prefix mechanism to lean on here — the core needs this
|
|
22
|
+
* explicitly to compute the tus base path and to strip it from incoming
|
|
23
|
+
* request URLs.
|
|
24
|
+
*/
|
|
25
|
+
basePath: string;
|
|
26
|
+
/**
|
|
27
|
+
* Whether `handler` should itself match/strip `basePath` from incoming
|
|
28
|
+
* request URLs. Defaults to `true` — correct for a raw
|
|
29
|
+
* `http.createServer` callback, or any host that hands `handler` the
|
|
30
|
+
* request's full, unmodified URL (unmatched paths 404). Set to `false`
|
|
31
|
+
* when mounting via a framework that already strips its own mount prefix
|
|
32
|
+
* before calling middleware — Express's `app.use(basePath, handler)`, or
|
|
33
|
+
* Connect/Meteor's `WebApp.connectHandlers.use(basePath, handler)` — so
|
|
34
|
+
* `handler` treats `req.url` as already relative to `basePath`. Either
|
|
35
|
+
* way, `basePath` is still used to build the tus `Location` header
|
|
36
|
+
* returned to clients.
|
|
37
|
+
*/
|
|
38
|
+
stripBasePath?: boolean;
|
|
39
|
+
/** Max TUS upload size in bytes. Required — consumers must choose an explicit cap. Use `Infinity` for no cap. */
|
|
40
|
+
maxUploadSize: number;
|
|
41
|
+
/** Which upload strategy this deployment expects. Purely advertised via `GET /capabilities`. Defaults to `"beat"`. */
|
|
42
|
+
uploadUnit?: 'beat' | 'merged';
|
|
43
|
+
/** File extensions allowed per artifact kind. See the Fastify plugin's `allowedExtensions` for the full shape. */
|
|
44
|
+
allowedExtensions?: PulseVaultAllowedExtensionsInput;
|
|
45
|
+
/** Cache-control options forwarded to `@fastify/send` for the GET route. */
|
|
46
|
+
cache?: PulseVaultCoreCacheOptions;
|
|
47
|
+
/** Optional authorization hook. See the Fastify plugin's `authorize` option for semantics. */
|
|
48
|
+
authorize?: PulseVaultAuthorize;
|
|
49
|
+
/** Optional payload-validation hook. See the Fastify plugin's `validatePayload` option for semantics. */
|
|
50
|
+
validatePayload?: PulseVaultValidatePayload;
|
|
51
|
+
/** Optional post-upload hook. See the Fastify plugin's `onUploadComplete` option for semantics. */
|
|
52
|
+
onUploadComplete?: PulseVaultOnUploadComplete;
|
|
53
|
+
/** Optional low-frequency event hook. See the Fastify plugin's `onArtifactEvent` option for semantics. */
|
|
54
|
+
onArtifactEvent?: PulseVaultOnArtifactEvent;
|
|
55
|
+
/** Logger for internal diagnostics (authorize rejections, tus handler failures). Defaults to `console`. */
|
|
56
|
+
logger?: PulseVaultLogger;
|
|
57
|
+
/** @deprecated Use `validatePayload` instead — see the Fastify plugin's option of the same name. */
|
|
58
|
+
validateProjectPayload?: PulseVaultValidatePayload;
|
|
59
|
+
/** @deprecated Use `onUploadComplete` instead — see the Fastify plugin's option of the same name. */
|
|
60
|
+
onProjectUploadComplete?: PulseVaultOnUploadComplete;
|
|
61
|
+
};
|
|
62
|
+
type ConnectNext = (err?: unknown) => void;
|
|
63
|
+
export type PulseVaultCore = {
|
|
64
|
+
/**
|
|
65
|
+
* Connect-style request handler — mount directly as Express middleware
|
|
66
|
+
* (`app.use(basePath, core.handler)`), Meteor middleware
|
|
67
|
+
* (`WebApp.connectHandlers.use(basePath, core.handler)`), or a bare
|
|
68
|
+
* `http.createServer` callback. `next` is optional so it also works as a
|
|
69
|
+
* raw `http.createServer((req, res) => core.handler(req, res))` handler.
|
|
70
|
+
*/
|
|
71
|
+
handler: (req: IncomingMessage, res: ServerResponse, next?: ConnectNext) => Promise<void>;
|
|
72
|
+
/** One-time teardown — calls `storage.shutdown?.()`. */
|
|
73
|
+
shutdown: () => Promise<void>;
|
|
74
|
+
/** Handles a TUS create/patch/head/delete request directly (any method under `/upload`). */
|
|
75
|
+
handleTus: (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
76
|
+
/** Writes the `GET /capabilities` JSON payload. */
|
|
77
|
+
handleCapabilities: (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
78
|
+
/** Resolves and streams/redirects `GET /artifacts/:artifactId`. */
|
|
79
|
+
handleArtifactGet: (req: IncomingMessage, res: ServerResponse, artifactId: string, token: string | undefined) => Promise<void>;
|
|
80
|
+
/** Handles `DELETE /artifacts/:artifactId`. */
|
|
81
|
+
handleArtifactDelete: (req: IncomingMessage, res: ServerResponse, artifactId: string) => Promise<void>;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Build the framework-agnostic core: the same authorize/validatePayload/
|
|
85
|
+
* onUploadComplete/onArtifactEvent orchestration, tus glue, capabilities
|
|
86
|
+
* payload, and artifact GET/DELETE logic the Fastify plugin uses, operating
|
|
87
|
+
* on raw `(req, res)` instead of Fastify's `request`/`reply` wrappers. Both
|
|
88
|
+
* the Fastify plugin and this factory ultimately call into the same
|
|
89
|
+
* `lib/pulsevaultTus.js` tus server, so behavior can't drift between them.
|
|
90
|
+
*/
|
|
91
|
+
export declare function createPulseVaultCore(options: PulseVaultCoreOptions): PulseVaultCore;
|
|
92
|
+
export { createLocalStorage } from './storage/local.js';
|
|
93
|
+
export type { LocalStorage, LocalStorageOptions } from './storage/local.js';
|
|
94
|
+
export { createS3Storage } from './storage/s3.js';
|
|
95
|
+
export type { S3Storage, S3StorageOptions } from './storage/s3.js';
|
|
96
|
+
export type { PulseVaultResolution, PulseVaultStorage, ReserveUploadParams, UploadKind, } from './storage/types.js';
|
|
97
|
+
export type { PulseVaultAuthorize, PulseVaultAuthorizeContext, PulseVaultAuthorizePhase, } from './lib/authorize.js';
|
|
98
|
+
export type { PulseVaultOnUploadComplete, PulseVaultOnArtifactEvent, PulseVaultArtifactEvent, } from './lib/pulsevaultTus.js';
|
|
99
|
+
export { sniffMp4, createMp4Sniffer, createS3Mp4Sniffer } from './lib/magic.js';
|
|
100
|
+
export type { PulseVaultValidatePayload } from './lib/magic.js';
|
|
101
|
+
export { buildUploadLink } from './lib/deeplinks.js';
|
|
102
|
+
export type { UploadLinkOptions } from './lib/deeplinks.js';
|
|
103
|
+
export { issueCapabilityToken, verifyCapabilityToken, createCapabilityAuthorize, } from './lib/capability-token.js';
|
|
104
|
+
export type { CapabilityTokenClaims, IssueCapabilityTokenOptions, VerifyCapabilityTokenOptions, LookupSecret, } from './lib/capability-token.js';
|
|
105
|
+
export { createChecksumValidator, createS3ChecksumValidator, parseChecksumMetadata, } from './lib/checksum.js';
|
|
106
|
+
export type { ChecksumAlgorithm, ParsedChecksum } from './lib/checksum.js';
|
|
107
|
+
export { type PulseVaultRequest, type PulseVaultLogger } from './lib/request.js';
|
|
108
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}
|