frontpage-host 0.3.13 → 0.3.14

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/AGENTS.md CHANGED
@@ -299,3 +299,19 @@ For a manual group, `groups.people` accepts `availability: "all" | "available" |
299
299
  Complete Store edits: use existing items update --file with changed fields and variantUpdates. stock requires expectedStock from a fresh items get. One transaction saves all changes or none. On 409 review current stock; never silently substitute it. firstVariant plus optionNames enables versions. Keep explicit stock/variant commands for single operations. Routines add accepts --request-id UUID; reuse that ID and exact schedule after a lost response. Ordinary form edits live only in the active task; Cancel keeps input, Discard loses unfinished input. Submitted payments, imports, builds, and API-key status are separate operations.
300
300
 
301
301
  Template history (frontpage-host 0.3.11+): read `mail template get ID` before editing. `mail template history ID --limit 20 --cursor CURSOR` pages saved copies; `mail template history-get ID --history-id COPY_ID` fetches full content. Edit any copy, then `mail template set ID --file content.json` with the stable template ID and content fields only to make a new latest copy. Last template save wins; past copies remain. Campaign and series conflict checks remain. Retry uncertain saves through `mail save` with the same requestKey and exact payload. History begins with content retained at launch; earlier overwritten edits are unavailable. History reads use the plan’s Rewind window and always include Latest, even when older. Older copies stay stored; lists and direct reads apply the same limit. Window metadata explains the limit and whether older copies exist. See MAIL.md.
302
+
303
+ ## Uploaded video preparation
304
+
305
+ The current CLI attempts browser-compatible H.264 MP4 preparation after a local video
306
+ upload. This applies to `frontpage media upload` and `frontpage prompt --attach ./clip.mov`.
307
+ Use the returned `sitePath`; do not reconstruct a path from the original filename.
308
+ A successful conversion returns `prepared:true` and the MP4's actual filename, size and
309
+ URL. If preparation fails, the original remains usable as an upload with `prepared:false`
310
+ and a compatibility warning. Warnings print on stderr and appear in JSON success data.
311
+ An original's MP4/MOV extension does not establish browser compatibility.
312
+
313
+ `frontpage media list` and the website agent's `list_site_assets` prefer a completed
314
+ prepared copy over its exact original. Different uploads with the same display name
315
+ remain distinct. Existing URLs and published videos are not converted automatically.
316
+ Upgrade the CLI to receive upload-time preparation. Source path and access denials
317
+ remain errors; they do not become original-file fallback successes.
package/README.md CHANGED
@@ -122,3 +122,19 @@ GPT 6 Luna is the default for new website runs. Explicit site model preferences
122
122
  ### Template history
123
123
 
124
124
  Template history (0.3.11+): `frontpage mail template history ID` lists saved copies; `history-get ID --history-id COPY_ID` reads full content. Edit any copy and save with `template set ID --file content.json` to make it latest. Use the stable template ID, read current content before editing, and see [MAIL.md](./MAIL.md#template-history) for paging, access and retry-safe saves.
125
+
126
+ ## Uploaded video preparation
127
+
128
+ The current CLI attempts browser-compatible H.264 MP4 preparation after a local video
129
+ upload. This applies to `frontpage media upload` and `frontpage prompt --attach ./clip.mov`.
130
+ Use the returned `sitePath`; do not reconstruct a path from the original filename.
131
+ A successful conversion returns `prepared:true` and the MP4's actual filename, size and
132
+ URL. If preparation fails, the original remains usable as an upload with `prepared:false`
133
+ and a compatibility warning. Warnings print on stderr and appear in JSON success data.
134
+ An original's MP4/MOV extension does not establish browser compatibility.
135
+
136
+ `frontpage media list` and the website agent's `list_site_assets` prefer a completed
137
+ prepared copy over its exact original. Different uploads with the same display name
138
+ remain distinct. Existing URLs and published videos are not converted automatically.
139
+ Upgrade the CLI to receive upload-time preparation. Source path and access denials
140
+ remain errors; they do not become original-file fallback successes.
@@ -23,6 +23,7 @@ export type PromptAttachmentsPayload = {
23
23
  url: string;
24
24
  name?: string;
25
25
  sizeBytes?: number;
26
+ warning?: string;
26
27
  }>;
27
28
  };
28
29
  export type MediaUploadResult = UploadedMedia;
@@ -101,8 +101,9 @@ export function addUploadResult(out, data) {
101
101
  if (!out.videos.some((x) => x.url === data.url)) {
102
102
  out.videos.push({
103
103
  url: data.url,
104
- name,
104
+ name: data.prepared ? data.filename ?? name : name,
105
105
  sizeBytes: data.sizeBytes,
106
+ ...(data.warning ? { warning: data.warning } : {}),
106
107
  });
107
108
  }
108
109
  return;
@@ -122,7 +123,7 @@ export async function uploadLocalForAttach(slug, filePath) {
122
123
  return uploadLocalMedia({ slug, filePath });
123
124
  }
124
125
  export async function resolveSitePathUrl(slug, sitePath) {
125
- const data = await v1Get(`/api/v1/sites/${encodeURIComponent(slug)}/media`);
126
+ const data = await v1Get(`/api/v1/sites/${encodeURIComponent(slug)}/media?path=${encodeURIComponent(sitePath.replace(/\/+/g, "/").replace(/\/$/, ""))}`);
126
127
  const norm = (p) => p.replace(/\/+/g, "/").replace(/\/$/, "") || p;
127
128
  const want = norm(sitePath);
128
129
  const hit = data.assets.find((a) => a.sitePath === sitePath || norm(a.sitePath) === want);
@@ -8,6 +8,8 @@ export type UploadedMedia = {
8
8
  contentType?: string;
9
9
  content?: string;
10
10
  transport?: "proxy" | "client";
11
+ prepared?: boolean;
12
+ warning?: string;
11
13
  };
12
14
  /** Upload a local file using the Phase E transport matrix. */
13
15
  export declare function uploadLocalMedia(args: {
@@ -5,7 +5,7 @@ import { randomUUID } from "node:crypto";
5
5
  import { readFile } from "node:fs/promises";
6
6
  import { basename } from "node:path";
7
7
  import { put } from "@vercel/blob/client";
8
- import { apiBase, CliHttpError, EXIT_AUTH, EXIT_UNEXPECTED, EXIT_USAGE, getBearerAuthHeader, httpErrorFromV1, v1PostMultipart, } from "../http/client.js";
8
+ import { apiBase, CliHttpError, EXIT_AUTH, EXIT_UNEXPECTED, EXIT_USAGE, getBearerAuthHeader, httpErrorFromV1, v1PostMultipart, v1Post, } from "../http/client.js";
9
9
  import { contentTypeForExt, sitePathFromKey } from "./limits.js";
10
10
  import { selectMediaTransport } from "./select-transport.js";
11
11
  async function requestClientToken(args) {
@@ -81,7 +81,7 @@ async function uploadViaClient(args) {
81
81
  multipart,
82
82
  });
83
83
  const key = blob.pathname.replace(/^\//, "");
84
- return {
84
+ const original = {
85
85
  kind: args.kind,
86
86
  url: blob.url,
87
87
  key,
@@ -91,8 +91,28 @@ async function uploadViaClient(args) {
91
91
  contentType: args.contentType || contentTypeForExt(args.ext),
92
92
  transport: "client",
93
93
  };
94
+ if (args.kind !== "video")
95
+ return original;
96
+ try {
97
+ const prepared = await v1Post(`/api/v1/sites/${encodeURIComponent(args.slug)}/media/prepare`, { key, filename: args.filename }, { timeoutMs: 110000 });
98
+ if (typeof prepared.url !== "string" || typeof prepared.sitePath !== "string" || typeof prepared.filename !== "string" || typeof prepared.prepared !== "boolean")
99
+ throw new Error("Invalid video preparation response");
100
+ const result = { ...prepared, transport: "client" };
101
+ if (result.warning)
102
+ console.error(result.warning);
103
+ return result;
104
+ }
105
+ catch (error) {
106
+ if (error instanceof CliHttpError && error.status >= 400 && error.status < 500 && ![408, 429].includes(error.status))
107
+ throw error;
108
+ const warning = "Uploaded original video. Some browsers may not play this format.";
109
+ console.error(warning);
110
+ return { ...original, prepared: false, warning };
111
+ }
94
112
  }
95
113
  catch (err) {
114
+ if (err instanceof CliHttpError)
115
+ throw err;
96
116
  const msg = err instanceof Error ? err.message : String(err);
97
117
  throw new CliHttpError(`Upload failed: ${msg}`, EXIT_UNEXPECTED, 500);
98
118
  }
package/dist/registry.js CHANGED
@@ -407,6 +407,9 @@ export const COMMANDS = [
407
407
  ],
408
408
  flags: [
409
409
  "Auto-selects proxy (≤4 MB) vs direct-to-Blob for large rasters/PDFs and all video",
410
+ "Video uploads then attempt browser-compatible MP4 preparation; use the returned sitePath",
411
+ "Preparation failure keeps the original with a stderr warning and prepared:false in JSON",
412
+ "media list prefers an exact completed prepared video over its original",
410
413
  "Human success: sitePath first (markup-safe), then url: (blob URL for debugging)",
411
414
  "Use sitePath (/__media/uploads/<slug>/…) in markup — never raw blob hosts in pages",
412
415
  "Text/CSV upload is inline only — not a media-library asset (no /__media link); --json omits full content",
package/llms.txt CHANGED
@@ -59,3 +59,5 @@ The workspace validates and saves unfinished group settings before opening email
59
59
  Complete Store edits: use existing items update --file with changed fields and variantUpdates. stock requires expectedStock from a fresh items get. One transaction saves all changes or none. On 409 review current stock; never silently substitute it. firstVariant plus optionNames enables versions. Keep explicit stock/variant commands for single operations. Routines add accepts --request-id UUID; reuse that ID and exact schedule after a lost response. Ordinary form edits live only in the active task; Cancel keeps input, Discard loses unfinished input. Submitted payments, imports, builds, and API-key status are separate operations.
60
60
 
61
61
  Template history (frontpage-host 0.3.11+): read `mail template get ID` before editing. `mail template history ID --limit 20 --cursor CURSOR` pages saved copies; `mail template history-get ID --history-id COPY_ID` fetches full content. Edit any copy, then `mail template set ID --file content.json` with the stable template ID and content fields only to make a new latest copy. Last template save wins; past copies remain. Campaign and series conflict checks remain. Retry uncertain saves through `mail save` with the same requestKey and exact payload. History begins with content retained at launch; earlier overwritten edits are unavailable. History reads use the plan’s Rewind window and always include Latest, even when older. Older copies stay stored; lists and direct reads apply the same limit. Window metadata explains the limit and whether older copies exist. See MAIL.md.
62
+
63
+ Video uploads: the current CLI prepares a browser-compatible MP4 after uploading a local video, including prompt --attach. Use the returned sitePath and actual filename. prepared:false plus warning means the original was retained and playback compatibility is not assured. media list prefers an exact completed prepared copy. Existing video URLs are unchanged. See AGENTS.md for the upload and fallback contract.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frontpage-host",
3
- "version": "0.3.13",
3
+ "version": "0.3.14",
4
4
  "description": "Frontpage CLI — manage your site from the terminal",
5
5
  "type": "module",
6
6
  "bin": {