@feralfile/cli 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feralfile/cli",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "CLI for building, signing, and playing DP-1 playlists of digital art on Feral File devices",
5
5
  "repository": {
6
6
  "type": "git",
@@ -59,12 +59,20 @@ const { signPlaylist } = require('../utilities/playlist-signer');
59
59
  * can redirect the user instead of silently wrapping, say, an Art Blocks
60
60
  * collection *page* as a web item. Returns null for anything `play` should
61
61
  * handle itself (plain URLs and file paths parse to null here).
62
+ *
63
+ * A recognized-but-`unsupported` result (e.g. a legacy Art Blocks
64
+ * `/projects/{id}` URL, or an unsupported-chain OpenSea link) is also a
65
+ * discovery input — it's a marketplace URL, not a playable file — so it is
66
+ * redirected to `find` too, which surfaces the specific reason.
62
67
  */
63
68
  function describeDiscoveryInput(source) {
64
69
  const parsed = (0, marketplace_url_1.parseFindInput)(source);
65
- if (!parsed || parsed.kind === 'unsupported') {
70
+ if (!parsed) {
66
71
  return null;
67
72
  }
73
+ if (parsed.kind === 'unsupported') {
74
+ return 'a marketplace URL';
75
+ }
68
76
  switch (parsed.kind) {
69
77
  case 'token':
70
78
  return 'an on-chain token reference';
@@ -534,18 +534,37 @@ function validateDP1Playlist(playlist) {
534
534
  * misclassified HTML pages and extensionless URLs as static images, stamping
535
535
  * them with a display duration that cut interactive artworks off.)
536
536
  *
537
+ * The extension is taken from the URL *pathname* only — the query string and
538
+ * fragment are stripped first, so a signed URL like `art.png?sig=a.b` or
539
+ * `clip.mp4#t=1` still resolves to its real extension instead of parsing `b`
540
+ * or `mp4#t=1`. Misreading those would mislabel media as undetermined and
541
+ * (via buildUrlItem) route it through the interactive-web timing path.
542
+ *
537
543
  * @param {string} url - Media or page URL
538
544
  * @returns {string} MIME type, or '' when undetermined
539
545
  * @example
540
- * detectMimeType('https://example.com/image.png'); // 'image/png'
541
- * detectMimeType('https://example.com/art.html'); // 'text/html'
542
- * detectMimeType('https://example.com/output/abc'); // ''
546
+ * detectMimeType('https://example.com/image.png'); // 'image/png'
547
+ * detectMimeType('https://example.com/art.png?sig=a.b'); // 'image/png'
548
+ * detectMimeType('https://example.com/art.html'); // 'text/html'
549
+ * detectMimeType('https://example.com/output/abc'); // ''
543
550
  */
544
551
  function detectMimeType(url) {
545
552
  if (!url) {
546
553
  return '';
547
554
  }
548
- const extension = url.split('.').pop()?.toLowerCase().split('?')[0];
555
+ // Use the pathname only: drop query + fragment so a dot inside `?sig=a.b`
556
+ // or `#v=1.2` can't masquerade as the file extension.
557
+ let pathname;
558
+ try {
559
+ pathname = new URL(url).pathname;
560
+ }
561
+ catch {
562
+ // Not an absolute URL (bare path/filename) — strip fragment then query.
563
+ pathname = String(url).split('#')[0].split('?')[0];
564
+ }
565
+ const lastSegment = pathname.split('/').pop() || '';
566
+ const dotIndex = lastSegment.lastIndexOf('.');
567
+ const extension = dotIndex >= 0 ? lastSegment.slice(dotIndex + 1).toLowerCase() : '';
549
568
  const mimeTypes = {
550
569
  jpg: 'image/jpeg',
551
570
  jpeg: 'image/jpeg',
@@ -36,7 +36,7 @@ Optional settings used where headless/browser‑like behavior is needed.
36
36
 
37
37
  Used for signing DP‑1 playlists.
38
38
 
39
- - `playlist.privateKey` (string, Ed25519 private key in hex or base64): Used by the `sign` command to create DP-1 v1.1.0 multi-signatures. The `verify` command may derive the matching public key from this value (or `PLAYLIST_PRIVATE_KEY`) when you omit `--public-key`; **dp1-js applies that derived key only when verifying legacy flat `signature` strings**, not when checking `signatures[]` envelopes. If that derivation fails, `verify` prints a warning on stderr and continues without derived key material. The derived public key is emitted as PEM so Node can decode it without ambiguity. Hex may include or omit the `0x` prefix. You can also set this via `PLAYLIST_PRIVATE_KEY` in `.env`. `play` verifies playlists before delivery and only auto-signs the synthesized media URL fallback when signing is configured. `send` and `publish` verify before delivery or upload and reject unsigned or broken playlists.
39
+ - `playlist.privateKey` (string, Ed25519 private key in hex or base64): Used by the `sign` command to create DP-1 v1.1.0 multi-signatures. The `verify` command may derive the matching public key from this value (or `PLAYLIST_PRIVATE_KEY`) when you omit `--public-key`; **dp1-js applies that derived key only when verifying legacy flat `signature` strings**, not when checking `signatures[]` envelopes. If that derivation fails, `verify` prints a warning on stderr and continues without derived key material. The derived public key is emitted as PEM so Node can decode it without ambiguity. Hex may include or omit the `0x` prefix. You can also set this via `PLAYLIST_PRIVATE_KEY` in `.env`. `play` verifies playlists before delivery and only auto-signs the synthesized media URL fallback when signing is configured. `play` and `publish` verify before delivery or upload and reject unsigned or broken playlists.
40
40
 
41
41
  **Signing and key encoding:** Signing paths (`sign`, deterministic `build` when configured, and `-k/--key` overrides) pass the private key string through to **`dp1-js`** (`SignMultiEd25519`) without an extra decoding step in ff-cli. `dp1-js` recognizes **hex** (optional `0x`) or **base64** encodings of the PKCS#8 DER blob produced by the OpenSSL examples below, then loads the key for Ed25519. Use those formats; ff-cli does not add a separate normalizer ahead of the library.
42
42
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feralfile/cli",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "CLI for building, signing, and playing DP-1 playlists of digital art on Feral File devices",
5
5
  "repository": {
6
6
  "type": "git",