@mieweb/pulsevault 0.5.0 → 0.7.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +152 -1
  2. package/OPERATIONS.md +123 -46
  3. package/PROTOCOL.md +27 -5
  4. package/README.md +31 -8
  5. package/dist/app.d.ts +8 -7
  6. package/dist/app.d.ts.map +1 -1
  7. package/dist/app.js +4 -3
  8. package/dist/app.js.map +1 -1
  9. package/dist/core.d.ts +23 -9
  10. package/dist/core.d.ts.map +1 -1
  11. package/dist/core.js +106 -21
  12. package/dist/core.js.map +1 -1
  13. package/dist/lib/completion.d.ts +22 -5
  14. package/dist/lib/completion.d.ts.map +1 -1
  15. package/dist/lib/completion.js +247 -35
  16. package/dist/lib/completion.js.map +1 -1
  17. package/dist/lib/deeplinks.d.ts +18 -2
  18. package/dist/lib/deeplinks.d.ts.map +1 -1
  19. package/dist/lib/deeplinks.js +13 -2
  20. package/dist/lib/deeplinks.js.map +1 -1
  21. package/dist/lib/magic.d.ts +41 -1
  22. package/dist/lib/magic.d.ts.map +1 -1
  23. package/dist/lib/magic.js +104 -0
  24. package/dist/lib/magic.js.map +1 -1
  25. package/dist/lib/options.d.ts +2 -0
  26. package/dist/lib/options.d.ts.map +1 -1
  27. package/dist/lib/options.js +8 -4
  28. package/dist/lib/options.js.map +1 -1
  29. package/dist/lib/protocol-version.gen.js +1 -1
  30. package/dist/lib/pulsevaultTus.d.ts.map +1 -1
  31. package/dist/lib/pulsevaultTus.js +35 -1
  32. package/dist/lib/pulsevaultTus.js.map +1 -1
  33. package/dist/lib/web-ready.d.ts +145 -18
  34. package/dist/lib/web-ready.d.ts.map +1 -1
  35. package/dist/lib/web-ready.js +484 -91
  36. package/dist/lib/web-ready.js.map +1 -1
  37. package/dist/storage/local.d.ts +3 -1
  38. package/dist/storage/local.d.ts.map +1 -1
  39. package/dist/storage/local.js +310 -50
  40. package/dist/storage/local.js.map +1 -1
  41. package/dist/storage/s3.d.ts.map +1 -1
  42. package/dist/storage/s3.js +21 -1
  43. package/dist/storage/s3.js.map +1 -1
  44. package/dist/storage/types.d.ts +89 -4
  45. package/dist/storage/types.d.ts.map +1 -1
  46. package/dist/storage/types.js +7 -0
  47. package/dist/storage/types.js.map +1 -1
  48. package/package.json +2 -2
  49. package/protocol/openapi.json +26 -3
  50. package/protocol/schemas/artifact-status.schema.json +13 -1
  51. package/protocol/schemas/deep-link.schema.json +2 -2
  52. package/scripts/web-ready-migrate.mjs +35 -11
@@ -1,17 +1,20 @@
1
1
  #!/usr/bin/env node
2
- // Make every already-uploaded video artifact in a local-storage workspace
3
- // web-playable, in place. New uploads are handled by the `onUploadComplete`
4
- // web-ready hook (see examples/fastify-demo/server.mjs); this script is the
5
- // one-time backfill for artifacts that landed before the hook existed.
2
+ // Conform every already-uploaded video artifact in a local-storage workspace
3
+ // to the format PulseVault serves (`CONFORM_TARGET`). New uploads are handled
4
+ // by the `webReady` option; this script is the one-time backfill for
5
+ // artifacts that landed before it was on. Stop the server first: it caches
6
+ // each artifact's extension, which a container change rewrites.
6
7
  //
7
8
  // For each ready `kind: "video"` sidecar in `<workspaceDir>/.pulsevault/`:
8
- // - moov atom at the end of the file → lossless faststart remux (sub-second)
9
- // - non-H.264 video codec (e.g. HEVC) → one-time libx264 transcode
10
- // - already web-ready / not MP4 bytes → untouched
9
+ // - already in the target format → untouched
10
+ // - moov atom at the end of an MP4 → lossless faststart remux
11
+ // - off-target video or audio → one ffmpeg run (H.264/AAC, scaled, tone-mapped)
12
+ // - another container (WebM, MKV, MOV, …) → a new `<id>.mp4`; the sidecar
13
+ // switches to it and the original is deleted
11
14
  //
12
15
  // Rewrites are atomic (tmp file + rename), so interrupting the script never
13
16
  // corrupts an artifact — rerun it and it picks up where it left off (already
14
- // fixed files report `none` and are skipped for free).
17
+ // fixed files report `none`).
15
18
  //
16
19
  // Usage:
17
20
  // node scripts/web-ready-migrate.mjs <workspaceDir> [--dry-run] [--no-transcode]
@@ -46,7 +49,7 @@ try {
46
49
  process.exit(1);
47
50
  }
48
51
 
49
- const counts = { none: 0, remuxed: 0, transcoded: 0, skipped: 0, missing: 0 };
52
+ const counts = { none: 0, remuxed: 0, transcoded: 0, conformed: 0, skipped: 0, missing: 0 };
50
53
  let processed = 0;
51
54
 
52
55
  for (const sidecarFile of sidecarFiles) {
@@ -84,8 +87,29 @@ for (const sidecarFile of sidecarFiles) {
84
87
  continue;
85
88
  }
86
89
 
87
- const result = await ensureWebReady(filePath, { transcode, logger: console });
90
+ const { outputPath, ...result } = await ensureWebReady(filePath, { transcode, logger: console });
88
91
  counts[result.action] += 1;
92
+ // Record what was done on the sidecar, as the server does; a new container also switches the
93
+ // artifact to its `.mp4` (keeping the uploaded extension as `sourceExt`), then the original
94
+ // goes. Atomic tmp + rename, like the adapter's own sidecar writes.
95
+ // A rerun finds a converted file already in the format: keep what the conversion recorded,
96
+ // and finish what an interrupted run left: the original, once the sidecar names the `.mp4`.
97
+ if (result.action === "none" && sidecar.webReady) {
98
+ if (sidecar.sourceExt && sidecar.sourceExt !== sidecar.ext) {
99
+ await fs.rm(path.join(root, kind, `${artifactId}${sidecar.sourceExt}`), { force: true });
100
+ }
101
+ continue;
102
+ }
103
+ const next = { ...sidecar, converted: true, webReady: result };
104
+ if (outputPath) {
105
+ next.sourceExt = sidecar.sourceExt ?? sidecar.ext;
106
+ next.ext = path.extname(outputPath);
107
+ }
108
+ const sidecarPath = path.join(sidecarDir, sidecarFile);
109
+ const tmpPath = `${sidecarPath}.migrate.tmp`;
110
+ await fs.writeFile(tmpPath, JSON.stringify(next), "utf8");
111
+ await fs.rename(tmpPath, sidecarPath);
112
+ if (outputPath) await fs.rm(filePath, { force: true });
89
113
  if (result.action !== "none") {
90
114
  console.log(`${result.action.padEnd(11)} ${artifactId} (${result.reason})`);
91
115
  }
@@ -96,7 +120,7 @@ if (dryRun) {
96
120
  } else {
97
121
  console.log(
98
122
  `\nDone: ${processed} ready video artifact(s) — ` +
99
- `${counts.remuxed} remuxed, ${counts.transcoded} transcoded, ` +
123
+ `${counts.remuxed} remuxed, ${counts.transcoded} transcoded, ${counts.conformed} conformed, ` +
100
124
  `${counts.none} already web-ready, ${counts.skipped} skipped, ${counts.missing} missing.`,
101
125
  );
102
126
  }