@songsid/agend 2.2.0-beta.17 → 2.2.0-beta.19

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 (59) hide show
  1. package/README.md +18 -18
  2. package/README.zh-TW.md +18 -18
  3. package/dist/agent-whats-new.js +3 -1
  4. package/dist/agent-whats-new.js.map +1 -1
  5. package/dist/backend/kiro.d.ts +2 -0
  6. package/dist/backend/kiro.js +4 -0
  7. package/dist/backend/kiro.js.map +1 -1
  8. package/dist/backend/types.d.ts +5 -0
  9. package/dist/backend/types.js.map +1 -1
  10. package/dist/cli.js +1 -1
  11. package/dist/cli.js.map +1 -1
  12. package/dist/compact-watch.d.ts +9 -1
  13. package/dist/compact-watch.js +47 -6
  14. package/dist/compact-watch.js.map +1 -1
  15. package/dist/config-validator.js +26 -1
  16. package/dist/config-validator.js.map +1 -1
  17. package/dist/daemon.d.ts +8 -0
  18. package/dist/daemon.js +65 -5
  19. package/dist/daemon.js.map +1 -1
  20. package/dist/fleet-manager.js +49 -20
  21. package/dist/fleet-manager.js.map +1 -1
  22. package/dist/forged-envelope-scan.d.ts +4 -3
  23. package/dist/forged-envelope-scan.js +4 -3
  24. package/dist/forged-envelope-scan.js.map +1 -1
  25. package/dist/install-lock.d.ts +18 -1
  26. package/dist/install-lock.js +30 -3
  27. package/dist/install-lock.js.map +1 -1
  28. package/dist/kiro-compact-pane.d.ts +38 -0
  29. package/dist/kiro-compact-pane.js +57 -0
  30. package/dist/kiro-compact-pane.js.map +1 -0
  31. package/dist/locale.js +4 -4
  32. package/dist/locale.js.map +1 -1
  33. package/dist/outbound-schemas.js +1 -1
  34. package/dist/outbound-schemas.js.map +1 -1
  35. package/dist/public-web-gateway.d.ts +2 -0
  36. package/dist/public-web-gateway.js +6 -1
  37. package/dist/public-web-gateway.js.map +1 -1
  38. package/dist/types.d.ts +8 -0
  39. package/dist/ui/chat-render.js +31 -6
  40. package/dist/ui/chat-store.js +5 -5
  41. package/dist/ui/chat-strings.js +6 -2
  42. package/dist/ui/chat-thread.js +15 -2
  43. package/dist/ui/panel-chat.js +1 -1
  44. package/dist/ui/panel-settings.js +1 -1
  45. package/dist/ui/shared/app.css +7 -0
  46. package/dist/update-launch.d.ts +3 -1
  47. package/dist/update-launch.js +6 -1
  48. package/dist/update-launch.js.map +1 -1
  49. package/dist/web-api.d.ts +4 -0
  50. package/dist/web-api.js +135 -43
  51. package/dist/web-api.js.map +1 -1
  52. package/dist/web-chat-history.d.ts +14 -0
  53. package/dist/web-chat-history.js +18 -1
  54. package/dist/web-chat-history.js.map +1 -1
  55. package/dist/web-upload.d.ts +112 -1
  56. package/dist/web-upload.js +237 -36
  57. package/dist/web-upload.js.map +1 -1
  58. package/launcher/install-admission.cjs +61 -6
  59. package/package.json +3 -3
@@ -86,7 +86,20 @@ export function createThread(list, scroller, opts) {
86
86
  const ticks = u && x.delivery ? R().deliveryHtml(x.delivery, TICKS()) : "";
87
87
  const tools = u ? "" : `<div class="msg-tools"><button type="button" class="chip-btn icon-only" data-act="copyMsg" data-arg="${escAttr(msgKey(x))}" title="${escAttr(tr("chat.copyMessage"))}" aria-label="${escAttr(tr("chat.copyMessage"))}">${COPY}</button></div>`;
88
88
  const buttons = x.role === "agent" ? replyButtonsHtml(x.buttons) : "";
89
- return `<div class="msg ${u ? "user" : "agent"}"><div class="meta"><span class="sender">${escAttr(x.sender)}</span>${time}${ticks}</div><div class="body"><div class="md">${R().renderMarkdown(x.text, { htmlCards: x.role === "agent", emojis: opts.emojis, mentions: opts.mentions })}</div>${R().attachmentsHtml(x.attachments, { htmlCards: x.role === "agent", goneTitle: tr("chat.attGone"), goneLabel: tr("chat.attUnavailable"), inlinePreviews: !PUBLIC_LINK() })}${buttons}</div>${tools}</div>`;
89
+ // A person's click on a reply button shows as the button's label, never the line the agent was given (its value).
90
+ const clicked = x.role === "user" && x.click && typeof x.click.label === "string";
91
+ return `<div class="msg ${u ? "user" : "agent"}"><div class="meta"><span class="sender">${escAttr(x.sender)}</span>${time}${ticks}</div><div class="body">${clicked ? clickHtml(x.click) : `<div class="md">${R().renderMarkdown(x.text, { htmlCards: x.role === "agent", emojis: opts.emojis, mentions: opts.mentions })}</div>`}${R().attachmentsHtml(x.attachments, { htmlCards: x.role === "agent", goneTitle: tr("chat.attGone"), goneLabel: tr("chat.attUnavailable"), inlinePreviews: !PUBLIC_LINK() })}${buttons}</div>${tools}</div>`;
92
+ }
93
+ /**
94
+ * A button click as a chip: 🔘 and the label (escaped: the label is the agent's text). With `of` (live, while its
95
+ * reply is in this thread) it is a button that shows that reply; restored from disk, plain.
96
+ */
97
+ function clickHtml(click) {
98
+ const inner = `<span class="click-mark" aria-hidden="true">🔘</span><span class="sr-only">${escAttr(tr("chat.clicked"))} </span>${escAttr(click.label)}`;
99
+ const of = typeof click.of === "string" && /^[0-9a-f]{32}$/.test(click.of) ? click.of : null;
100
+ return `<div class="click-chip">${of
101
+ ? `<button type="button" class="click-link" data-act="showButtons" data-arg="${escAttr(of)}" title="${escAttr(tr("chat.clickShow"))}">${inner}</button>`
102
+ : `<span class="click-text">${inner}</span>`}</div>`;
90
103
  }
91
104
  /**
92
105
  * #1672: a status line (another instance's message, a daemon notice) is muted, read-only plain text — never Markdown,
@@ -592,7 +605,7 @@ export function createThread(list, scroller, opts) {
592
605
  else if (act === "replyButton") {
593
606
  const m = /^([0-9a-f]{32}):(\d{1,2})$/.exec(el.dataset.arg || "");
594
607
  if (m && opts.clickReplyButton) opts.clickReplyButton(m[1], Number(m[2]));
595
- }
608
+ } else if (act === "showButtons") { const x = msgs.find(y => y.buttons && y.buttons.id === el.dataset.arg); if (x) reveal(msgKey(x)); }
596
609
  }
597
610
 
598
611
  /** The thread goes (the chat left, or another instance opened): every preview in it stops first. */
@@ -324,7 +324,7 @@ function CommandCard({ name, lease }) {
324
324
  ${c.text ? html`<pre class="cmd-text">${c.text}</pre>` : null}
325
325
  ${c.compact ? html`<p class="cmd-text cmd-phase">${c.compact === "running" ? t("chat.compactRunning")
326
326
  : c.compact === "done" ? t("chat.compactDone") : c.compact === "timeout" ? t("chat.compactTimeout", "10")
327
- : c.compact === "lost" ? t("chat.compactLost") : t("chat.compactUnknown")}</p>` : null}
327
+ : c.compact === "lost" ? t("chat.compactLost") : c.compact === "not_compacted" ? t("chat.compactNotCompacted") : t("chat.compactUnknown")}</p>` : null}
328
328
  ${c.choices && c.choices.prompt ? html`<pre class="cmd-text">${c.choices.prompt}</pre>` : null}
329
329
  ${c.choices ? html`<div class="cmd-choices" role="group" aria-label=${t("chat.cmdChoose")}>${c.choices.options.map((o) => html`<button key=${o.id} type="button"
330
330
  class=${`btn btn-sm${o.id === c.choices.current ? " current" : ""}`} aria-current=${o.id === c.choices.current ? "true" : undefined} onClick=${() => run(o.id)}>${o.label}</button>`)}</div>` : null}
@@ -761,7 +761,7 @@ function General({ ctx }) {
761
761
  */
762
762
  export const WEB_READ_ONLY = [
763
763
  "web.allowed_hosts", "web.view_access", "web.notify_login", "web.preview", "web.preview_port", "web.preview_origin", "web.preview_on_public_link",
764
- "web.usage_panel", "web.provider_secrets", "web_terminal.bind", "web_terminal.tunnel",
764
+ "web.usage_panel", "web.provider_secrets", "web.upload_max_file_mb", "web.upload_max_total_mb", "web_terminal.bind", "web_terminal.tunnel",
765
765
  ];
766
766
  function WebSection({ ctx, staged }) {
767
767
  const { schema } = ctx;
@@ -382,6 +382,13 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
382
382
  such as 「昨天 下午03:58」, ticks) — and a block body would stretch to it; fit-content keeps a short message short, on
383
383
  the right under its meta, and a long one still wraps at the message's max-width. */
384
384
  .msg.user .body { background: var(--user-bubble); border-radius: var(--r-xl); padding: 10px var(--s-4); width: fit-content; max-width: 100%; margin-left: auto; }
385
+ /* A person's click on a reply button: the bubble shows 🔘 and the button's label (never the value the agent was given);
386
+ live, the label is a button that shows the reply its buttons were on. */
387
+ .click-chip { display: flex; }
388
+ .click-chip .click-link, .click-chip .click-text { display: inline-flex; align-items: baseline; gap: var(--s-1); padding: 0; border: 0; background: none; color: inherit; font: inherit; text-align: left; overflow-wrap: anywhere; }
389
+ .click-chip .click-link { cursor: pointer; }
390
+ .click-chip .click-link:hover, .click-chip .click-link:focus-visible { text-decoration: underline; }
391
+ .click-mark { flex: none; }
385
392
  .msg.agent { align-self: stretch; }
386
393
  /* #1672: a status line (another instance's message, a daemon notice): muted plain text, no bubble; a long one folds.
387
394
  Its class is `status-line`, never `status`: that is the header's inline-flex badge class, and on a message it turned
@@ -9,7 +9,9 @@ export declare const UPDATE_LOG_FILE_CAP: number;
9
9
  export declare function updateLogPath(dataDir: string): string;
10
10
  /**
11
11
  * Extract a short human-readable cause from raw updater output.
12
- * Prefers the last `npm ERR!`/`npm error` summary line or the last `✗` line.
12
+ * #1947: AgEnD's own install refusal first — the postinstall's "AgEnD cannot be installed here: …" or the preinstall's
13
+ * "AgEnD 2.2 needs Node …" — which npm prints after its `code`/`path` lines (prefixed `npm error`), so it was never
14
+ * shown. Then the last `npm ERR!`/`npm error` summary line or the last `✗` line.
13
15
  * Falls back to the last non-blank line. Masks secrets and caps at ~300 chars.
14
16
  */
15
17
  export declare function extractUpdateCause(output: string): string | null;
@@ -21,7 +21,9 @@ export function updateLogPath(dataDir) {
21
21
  }
22
22
  /**
23
23
  * Extract a short human-readable cause from raw updater output.
24
- * Prefers the last `npm ERR!`/`npm error` summary line or the last `✗` line.
24
+ * #1947: AgEnD's own install refusal first — the postinstall's "AgEnD cannot be installed here: …" or the preinstall's
25
+ * "AgEnD 2.2 needs Node …" — which npm prints after its `code`/`path` lines (prefixed `npm error`), so it was never
26
+ * shown. Then the last `npm ERR!`/`npm error` summary line or the last `✗` line.
25
27
  * Falls back to the last non-blank line. Masks secrets and caps at ~300 chars.
26
28
  */
27
29
  export function extractUpdateCause(output) {
@@ -29,6 +31,9 @@ export function extractUpdateCause(output) {
29
31
  const lines = output.split("\n").map(l => l.trimEnd()).filter(l => Boolean(l) && !l.startsWith("---"));
30
32
  if (!lines.length)
31
33
  return null;
34
+ const refusal = lines.map(l => /^(?:npm (?:ERR!|error)\s+)?\s*(AgEnD cannot be installed here: .+|AgEnD 2\.2 needs Node .+)$/i.exec(l)?.[1]).find(Boolean);
35
+ if (refusal)
36
+ return maskSecrets(refusal).slice(0, 300);
32
37
  // npm ERR! ends with !, a non-word char: \b does not anchor here. Use (?:\s|$) instead.
33
38
  const npmErrRe = /^npm (ERR!|error)(?:\s|$)/i;
34
39
  const npmLines = lines.filter(l => npmErrRe.test(l));
@@ -1 +1 @@
1
- {"version":3,"file":"update-launch.js","sourceRoot":"","sources":["../src/update-launch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"update-launch.js","sourceRoot":"","sources":["../src/update-launch.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,OAAO,EAAE,QAAQ,EAAqB,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAa,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7H,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,CAAC,EAAE,MAAM,aAAa,CAAC;AAEhC,uGAAuG;AACvG,MAAM,gBAAgB,GAAG,CAAC,GAAG,IAAI,CAAC;AAClC,sEAAsE;AACtE,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,GAAG,IAAI,CAAC;AAE9C;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,OAAO,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,+DAA+D;IAC/D,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IACvG,IAAI,CAAC,KAAK,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,+FAA+F,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3J,IAAI,OAAO;QAAE,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACvD,wFAAwF;IACxF,MAAM,QAAQ,GAAG,4BAA4B,CAAC;IAC9C,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpB,6FAA6F;QAC7F,oEAAoE;QACpE,MAAM,OAAO,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7E,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;YACjB,MAAM,OAAO,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvF,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC5C,CAAC;QACD,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,6CAA6C,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAChG,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACnG,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACzC,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,IAAI,KAAK,CAAC,MAAM;QAAE,OAAO,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5E,OAAO,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC5D,CAAC;AAED,+GAA+G;AAC/G,SAAS,YAAY,CAAC,MAAc;IAClC,MAAM,EAAE,GAAG,qCAAqC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,gCAAgC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACzH,OAAO,EAAE,IAAI,8BAA8B,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;AAC1E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,OAAgC,EAAE;IAC9E,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,IAAI,CAAC,SAAS;QAAE,OAAO,mCAAmC,MAAM,IAAI,CAAC;IACzE,IAAI,wCAAwC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1D,MAAM,KAAK,GAAG,kCAAkC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,gDAAgD,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACzI,MAAM,IAAI,GAAG,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;eAC/D,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,UAAU,IAAI,0BAA0B,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QACjG,IAAI,IAAI;YAAE,OAAO,CAAC,CAAC,+BAA+B,EAAE,aAAa,KAAK,qBAAqB,CAAC,CAAC;QAC7F,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,wBAAwB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,6BAA6B,MAAM,qBAAqB,CAAC;IAC3G,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,MAAc;IAC3D,gGAAgG;IAChG,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,GAAG,mBAAmB,GAAG,CAAC,EAAE,CAAC;YAC5E,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;YAClC,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,mBAAmB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1F,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAC7B,IAAI,CAAC;QACH,cAAc,CAAC,OAAO,EAAE,GAAG,MAAM,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAC7B,IAAI,EAAU,CAAC;IACf,IAAI,CAAC;QACH,EAAE,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,CAAC,uDAAuD;IACtE,CAAC;IACD,4FAA4F;IAC5F,IAAI,CAAC;QAAC,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAC1D,qFAAqF;IACrF,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;QAAC,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,CAAC,CAAC;IAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACxF,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;AACxB,CAAC;AAED;;;GAGG;AACH,SAAS,WAAW,CAAC,OAAe,EAAE,MAAc;IAClD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACtC,OAAO,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC7F,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;AAC1B,CAAC;AASD,MAAM,CAAC,MAAM,uBAAuB,GAAqB;IACvD,QAAQ,EAAE,OAAO,CAAC,QAAQ;IAC1B,MAAM,EAAE,KAAK,IAAI,EAAE;QACjB,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,mBAAmB,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5G,IAAI,WAAW,CAAC,GAAG,EAAE,GAAG,OAAO,IAAI,IAAI;YAAE,MAAM,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC7E,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,EAAE,KAAK,IAAI,EAAE;QAClB,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC,aAAa,EAAE,CAAC,WAAW,CAAC,EAAE;gBACzE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI;aACtD,CAAC,CAAC;YACH,OAAO,WAAW,CAAC,GAAG,EAAE,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5D,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,IAAI,CAAC;QAAC,CAAC;IAC1B,CAAC;IACD,KAAK,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;CAC7C,CAAC;AAEF,kFAAkF;AAClF,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACzE,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,8BAA8B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAC7F,0EAA0E;QAC1E,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAKD,sGAAsG;AACtG,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,KAAa,EAAE,OAAyB,uBAAuB;IACvG,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC;IAC7D,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QAAC,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;IAAC,CAAC;IACrC,MAAM,CAAC;QAAC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,wCAAwC,EAAE,CAAC;IAAC,CAAC;IACjF,MAAM,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IACxC,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,4CAA4C,EAAE,CAAC;IACjG,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC;IAC5C,IAAI,OAAsB,CAAC;IAC3B,IAAI,CAAC;QAAC,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,GAAG,IAAI,CAAC;IAAC,CAAC;IACjE,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1D,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,wEAAwE,EAAE,CAAC;IAC1I,yFAAyF;IACzF,+FAA+F;IAC/F,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAC3B,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,2CAA2C,EAAE,CAAC;IAC7G,IAAI,CAAC;QACH,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE,KAAK,MAAM;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,8DAA8D,EAAE,CAAC;IACnI,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,2CAA2C,EAAE,CAAC;IAAC,CAAC;IACtF,MAAM,KAAK,GAAG,iBAAiB,KAAK,QAAQ,CAAC;IAC7C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE;YACtD,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,KAAK,EAAE;YACnF,GAAG,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,IAAI;SACjD,EAAE,CAAC;AACN,CAAC;AAED,4GAA4G;AAC5G,MAAM,UAAU,iBAAiB,CAC/B,KAAiC,EACjC,IAA+B,EAC/B,OAAgB;AAChB,uEAAuE;AACvE,SAAkB;AAClB,gHAAgH;AAChH,SAAkB;IAElB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,aAAa,GAAG,SAAS,KAAK,SAAS,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC;IAEvE,MAAM,MAAM,GAAG,CAAC,MAAc,EAAE,EAAE;QAChC,IAAI,QAAQ;YAAE,OAAO;QACrB,QAAQ,GAAG,IAAI,CAAC;QAChB,MAAM,IAAI,GAAG,OAAO,IAAI,IAAI,IAAI,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC3F,MAAM,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAC9D,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,aAAa,IAAI,CAAC,UAAU,CAAC,SAAU,CAAC,EAAE,CAAC,CAAC;QAC/F,oGAAoG;QACpG,IAAI,CAAC;YACH,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC;YAC9D,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACtD,CAAC,CAAC,wBAAwB,EAAE,MAAM,CAAC;YACnC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACrD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACf,CAAC,CAAC;IAEF,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;IAC9D,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;QAClC,IAAI,MAAM,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,EAAE,CAAC,EAAE,CAAC;YAC1C,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,4BAA4B,CAAC;gBAC7C,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,qBAAqB,EAAE,IAAI,CAAC,CAAC,CAAC;QACrF,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
package/dist/web-api.d.ts CHANGED
@@ -39,6 +39,8 @@ export interface WebApiContext {
39
39
  web?: {
40
40
  echo_to_channel?: boolean;
41
41
  usage_panel?: boolean;
42
+ upload_max_file_mb?: number;
43
+ upload_max_total_mb?: number;
42
44
  };
43
45
  defaults?: {
44
46
  backend?: string;
@@ -294,6 +296,8 @@ export interface AppShellContext {
294
296
  web?: {
295
297
  usage_panel?: boolean;
296
298
  log_tab?: boolean;
299
+ upload_max_file_mb?: number;
300
+ upload_max_total_mb?: number;
297
301
  };
298
302
  } | null;
299
303
  /** #1665: the host's theme and language go into the page itself, so a device paints them before any script reads. */
package/dist/web-api.js CHANGED
@@ -15,7 +15,7 @@ import { isSafeInstanceName } from "./web-shell-routes.js";
15
15
  import { MAX_COMMAND_ARGS } from "./web-commands.js";
16
16
  import { sendPanelHtml } from "./web-host-guard.js";
17
17
  import { shellRoute } from "./web-shell-routes.js";
18
- import { readFileSync } from "node:fs";
18
+ import { createReadStream, createWriteStream, readFileSync } from "node:fs";
19
19
  import { join, dirname } from "node:path";
20
20
  import { fileURLToPath } from "node:url";
21
21
  import { CreateInstanceArgs, CreateScheduleArgs, UpdateScheduleArgs, validateArgs } from "./outbound-schemas.js";
@@ -26,7 +26,7 @@ import { z } from "zod";
26
26
  import { evaluateWebRequest, isPassiveWebRead, isSecureRequest, isWebRequestAuthorized, WEB_TOKEN_INVALID_MESSAGE } from "./web-auth.js";
27
27
  import { dashboardOriginFor } from "./web-preview.js";
28
28
  import { newWebMessageId, parseLastEventId } from "./web-chat-history.js";
29
- import { attachmentDelivery, displayName, INLINE_MIME, isFileId, MEDIA_RANGE_MAX, publicAttachment, sniffUpload, UPLOAD_LIMITS, wellFormed } from "./web-upload.js";
29
+ import { attachmentDelivery, createPartFile, displayName, fileTooLargeText, INLINE_MIME, isFileId, MEDIA_RANGE_MAX, publicAttachment, UPLOAD_LIMITS, UPLOAD_MAX_MS, UPLOAD_STALL_MS, UploadSniffer, uploadLimits, wellFormed } from "./web-upload.js";
30
30
  import { getAgendHome } from "./paths.js";
31
31
  import { OPERATOR } from "./web-prefs.js";
32
32
  import { WEB_NAME_FALLBACK } from "./web-profile.js";
@@ -442,12 +442,14 @@ export function handleWebRequest(req, res, url, ctx) {
442
442
  serveMediaRange(req, res, ctx.webFiles, id, media);
443
443
  return true;
444
444
  }
445
- const got = isFileId(id) ? ctx.webFiles?.read(id) : null;
446
- if (!got) {
445
+ // #1937: a file over MEDIA_RANGE_MAX streams from the descriptor its checks were made on — never whole in memory.
446
+ const big = isFileId(id) && (ctx.webFiles?.servedFile?.(id)?.size ?? 0) > MEDIA_RANGE_MAX ? ctx.webFiles?.open?.(id) ?? null : null;
447
+ const got = big ? null : isFileId(id) ? ctx.webFiles?.read(id) : null;
448
+ const file = big?.file ?? got?.file;
449
+ if (!file) {
447
450
  json(res, 404, { error: "No such file" });
448
451
  return true;
449
452
  }
450
- const { file, bytes } = got;
451
453
  const inline = INLINE_MIME.has(file.mime);
452
454
  // Only the four image types are shown in the page; anything else is a download, never rendered.
453
455
  res.setHeader("Content-Type", inline ? file.mime : (file.mime.startsWith("text/") ? "text/plain; charset=utf-8" : "application/octet-stream"));
@@ -455,8 +457,12 @@ export function handleWebRequest(req, res, url, ctx) {
455
457
  res.setHeader("X-Content-Type-Options", "nosniff");
456
458
  res.setHeader("Cache-Control", "private, no-store");
457
459
  res.setHeader("Content-Security-Policy", "default-src 'none'; img-src 'self'; style-src 'unsafe-inline'; sandbox");
460
+ if (big) {
461
+ streamWhole(res, big);
462
+ return true;
463
+ }
458
464
  res.writeHead(200);
459
- res.end(bytes);
465
+ res.end(got.bytes);
460
466
  return true;
461
467
  }
462
468
  // ── #1630: avatars and Discord server emoji, same-origin (the page never loads a platform's CDN; img-src stays 'self') ──
@@ -1622,6 +1628,11 @@ function handleSendMessage(req, res, ctx) {
1622
1628
  * One file for one instance's chat. The body is the file itself (Content-Type is ignored: the type is
1623
1629
  * read from the bytes), `X-Agend-Filename` its name for the label only. Stored in the instance's
1624
1630
  * workspace inbox under a name chosen here; answered with the id the message will name.
1631
+ *
1632
+ * #1937: streamed to a part file in that inbox (web-pending-….part) as it arrives — never held whole in memory — and
1633
+ * counted by the bytes that came, whatever Content-Length said. The limits are the ones in force for this request
1634
+ * (uploadLimits(): the config, and the public link's own cap). An upload that goes UPLOAD_STALL_MS without a byte, or
1635
+ * runs past UPLOAD_MAX_MS, is dropped; any upload that does not end in a stored file takes its part file with it.
1625
1636
  */
1626
1637
  function handleUpload(req, res, url, ctx) {
1627
1638
  const instance = url.searchParams.get("instance") ?? "";
@@ -1633,57 +1644,112 @@ function handleUpload(req, res, url, ctx) {
1633
1644
  json(res, 404, { error: `Instance not found: ${instance}` });
1634
1645
  return;
1635
1646
  }
1647
+ const limits = uploadLimits(ctx.fleetConfig?.web, { publicLink: gatewayRequestContext(req) !== undefined });
1648
+ const tooLarge = () => json(res, 413, { error: fileTooLargeText(limits), max_bytes: limits.maxFileBytes, ...(limits.publicLinkCapped ? { public_link: true } : {}) });
1636
1649
  const declared = Number(req.headers["content-length"] ?? NaN);
1637
- if (Number.isFinite(declared) && declared > UPLOAD_LIMITS.maxFileBytes) {
1638
- json(res, 413, { error: `a file can be at most ${UPLOAD_LIMITS.maxFileBytes / 1024 / 1024} MB` });
1650
+ if (Number.isFinite(declared) && declared > limits.maxFileBytes) {
1651
+ tooLarge();
1652
+ req.resume();
1653
+ return;
1654
+ }
1655
+ let part, fd, discard;
1656
+ try {
1657
+ ({ path: part, fd, discard } = createPartFile(join(getAgendHome(), "workspaces", instance, "inbox")));
1658
+ }
1659
+ catch (err) {
1660
+ ctx.logger.error({ err: err.message, instance }, "Web upload could not be stored");
1661
+ json(res, 500, { error: "the file could not be stored" });
1639
1662
  req.resume();
1640
1663
  return;
1641
1664
  }
1642
- const chunks = [];
1665
+ const out = createWriteStream(part, { fd, autoClose: true });
1666
+ const sniffer = new UploadSniffer();
1643
1667
  let size = 0;
1644
- let refused = false;
1668
+ let over = false; // ended without a stored file: no further write, and the part file goes
1669
+ let stall;
1670
+ const clocks = () => { clearTimeout(stall); clearTimeout(deadline); };
1671
+ /** Stop here: answer (when the client is still there), remove the part file, and stop a body still arriving. */
1672
+ const drop = (answer) => {
1673
+ if (over)
1674
+ return;
1675
+ over = true;
1676
+ clocks();
1677
+ answer?.();
1678
+ out.destroy();
1679
+ discard();
1680
+ if (!req.complete)
1681
+ req.destroy();
1682
+ };
1683
+ const armStall = () => { clearTimeout(stall); stall = setTimeout(() => drop(() => json(res, 408, { error: "the upload stalled — attach the file again" })), UPLOAD_STALL_MS); stall.unref?.(); };
1684
+ const deadline = setTimeout(() => drop(() => json(res, 408, { error: "the upload took too long — attach the file again" })), UPLOAD_MAX_MS);
1685
+ deadline.unref?.();
1686
+ armStall();
1687
+ out.on("error", (err) => { ctx.logger.error({ err: err.message, instance }, "Web upload could not be stored"); drop(() => json(res, 500, { error: "the file could not be stored" })); });
1688
+ out.on("drain", () => { if (!over)
1689
+ req.resume?.(); });
1645
1690
  req.on("data", (c) => {
1646
- if (refused)
1691
+ if (over)
1647
1692
  return;
1648
1693
  size += c.length;
1649
- if (size > UPLOAD_LIMITS.maxFileBytes) {
1650
- refused = true;
1651
- json(res, 413, { error: `a file can be at most ${UPLOAD_LIMITS.maxFileBytes / 1024 / 1024} MB` });
1652
- req.destroy();
1694
+ if (size > limits.maxFileBytes) {
1695
+ drop(tooLarge);
1653
1696
  return;
1654
1697
  }
1655
- chunks.push(c);
1698
+ armStall();
1699
+ sniffer.push(c);
1700
+ if (!out.write(c))
1701
+ req.pause?.();
1656
1702
  });
1657
- req.on("error", () => { });
1703
+ req.on("error", () => drop()); // the client went away
1704
+ req.on("close", () => { if (!over && req.complete === false)
1705
+ drop(); });
1706
+ // The instance is checked again now the whole body is here: it may have been deleted (and its files
1707
+ // forgotten) or stopped while the upload streamed in; storing now would bring its id back (#1252 review).
1708
+ // Still deliverable means: its IPC is up (a paused one is woken by the send) and it is still registered —
1709
+ // in fleet.yaml, or as a ClassicBot room in classicBot.yaml. Asked when the body ends and again just before storing.
1710
+ const deliverable = () => ctx.instanceIpcClients.has(instance) && (!!ctx.fleetConfig?.instances?.[instance] || ctx.isClassicInstance?.(instance) === true);
1711
+ const gone = () => drop(() => json(res, 404, { error: `Instance not found: ${instance}` }));
1658
1712
  req.on("end", () => {
1659
- if (!permitWebContinuation(req, res, ctx))
1713
+ if (over)
1660
1714
  return;
1661
- if (refused)
1715
+ clocks();
1716
+ if (!permitWebContinuation(req, res, ctx)) {
1717
+ drop();
1662
1718
  return;
1663
- const bytes = Buffer.concat(chunks);
1719
+ }
1664
1720
  const name = displayName(typeof req.headers["x-agend-filename"] === "string" ? req.headers["x-agend-filename"] : "", "file");
1665
- const type = sniffUpload(bytes, name);
1721
+ const type = sniffer.result(name);
1666
1722
  if (!type) {
1667
- json(res, 415, { error: "the file is empty" });
1723
+ drop(() => json(res, 415, { error: "the file is empty" }));
1668
1724
  return;
1669
1725
  }
1670
- // The instance is checked again now the whole body is here: it may have been deleted (and its files
1671
- // forgotten) or stopped while the upload streamed in; storing now would bring its id back (#1252 review).
1672
- // Still deliverable means: its IPC is up (a paused one is woken by the send) and it is still registered —
1673
- // in fleet.yaml, or as a ClassicBot room in classicBot.yaml.
1674
- const registered = !!ctx.fleetConfig?.instances?.[instance] || ctx.isClassicInstance?.(instance) === true;
1675
- if (!ctx.instanceIpcClients.has(instance) || !registered) {
1676
- json(res, 404, { error: `Instance not found: ${instance}` });
1726
+ if (!deliverable()) {
1727
+ gone();
1677
1728
  return;
1678
1729
  }
1679
- try {
1680
- const entry = ctx.webFiles.storeUpload({ instance, inboxDir: join(getAgendHome(), "workspaces", instance, "inbox"), bytes, name, type });
1681
- json(res, 200, publicAttachment(entry));
1682
- }
1683
- catch (err) {
1684
- ctx.logger.error({ err: err.message, instance }, "Web upload could not be stored");
1685
- json(res, 500, { error: "the file could not be stored" });
1686
- }
1730
+ out.end(() => {
1731
+ if (over)
1732
+ return;
1733
+ // The write's finish is another wait (Prism #1941 P2-1): the session or the public link may have ended in it.
1734
+ if (!permitWebContinuation(req, res, ctx)) {
1735
+ drop();
1736
+ return;
1737
+ }
1738
+ if (!deliverable()) {
1739
+ gone();
1740
+ return;
1741
+ }
1742
+ over = true;
1743
+ try {
1744
+ const entry = ctx.webFiles.storeUploadedFile({ instance, partPath: part, name, type });
1745
+ json(res, 200, publicAttachment(entry));
1746
+ }
1747
+ catch (err) {
1748
+ discard();
1749
+ ctx.logger.error({ err: err.message, instance }, "Web upload could not be stored");
1750
+ json(res, 500, { error: "the file could not be stored" });
1751
+ }
1752
+ });
1687
1753
  });
1688
1754
  }
1689
1755
  function shellPreview(req, ctx, mode) {
@@ -1701,6 +1767,15 @@ function shellPreview(req, ctx, mode) {
1701
1767
  * No Range, several, or one not in that form → 200 with the whole file, as every file is served (the Download link).
1702
1768
  * Inline, nosniff, no caching, and the route's own sandbox policy, as for every file.
1703
1769
  */
1770
+ /** #1937: a whole file (headers already set) streamed from the descriptor its checks were made on: 200, its length. */
1771
+ function streamWhole(res, opened) {
1772
+ res.setHeader("Content-Length", String(opened.file.size));
1773
+ res.writeHead(200);
1774
+ const stream = createReadStream("", { fd: opened.fd, start: 0, end: Math.max(0, opened.file.size - 1), autoClose: true });
1775
+ stream.on("error", () => res.destroy());
1776
+ res.on("close", () => stream.destroy());
1777
+ stream.pipe(res);
1778
+ }
1704
1779
  function serveMediaRange(req, res, files, id, file) {
1705
1780
  const total = file.size;
1706
1781
  const header = typeof req.headers.range === "string" ? req.headers.range.trim() : "";
@@ -1724,20 +1799,34 @@ function serveMediaRange(req, res, files, id, file) {
1724
1799
  }
1725
1800
  }
1726
1801
  end = ranged ? Math.min(end, total - 1, start + MEDIA_RANGE_MAX - 1) : total - 1;
1802
+ const mediaHeaders = () => {
1803
+ res.setHeader("Content-Type", file.mime);
1804
+ res.setHeader("Content-Disposition", `inline; filename*=UTF-8''${encodeURIComponent(wellFormed(file.name))}`);
1805
+ res.setHeader("Accept-Ranges", "bytes");
1806
+ res.setHeader("X-Content-Type-Options", "nosniff");
1807
+ res.setHeader("Cache-Control", "private, no-store");
1808
+ res.setHeader("Content-Security-Policy", "default-src 'none'; img-src 'self'; style-src 'unsafe-inline'; sandbox");
1809
+ };
1810
+ // #1937 (Prism #1941 P3-2): the whole of a file over MEDIA_RANGE_MAX (no Range asked) streams, as /ui/file's do.
1811
+ if (!ranged && total > MEDIA_RANGE_MAX) {
1812
+ const opened = files.open(id);
1813
+ if (!opened) {
1814
+ json(res, 404, { error: "No such file" });
1815
+ return;
1816
+ }
1817
+ mediaHeaders();
1818
+ streamWhole(res, opened);
1819
+ return;
1820
+ }
1727
1821
  const got = files.readSlice(id, start, end);
1728
1822
  if (!got || (!ranged && got.bytes.length !== total)) {
1729
1823
  json(res, 404, { error: "No such file" });
1730
1824
  return;
1731
1825
  }
1732
- res.setHeader("Content-Type", file.mime);
1733
- res.setHeader("Content-Disposition", `inline; filename*=UTF-8''${encodeURIComponent(wellFormed(file.name))}`);
1734
- res.setHeader("Accept-Ranges", "bytes");
1826
+ mediaHeaders();
1735
1827
  if (ranged)
1736
1828
  res.setHeader("Content-Range", `bytes ${got.start}-${got.end}/${total}`);
1737
1829
  res.setHeader("Content-Length", String(got.bytes.length));
1738
- res.setHeader("X-Content-Type-Options", "nosniff");
1739
- res.setHeader("Cache-Control", "private, no-store");
1740
- res.setHeader("Content-Security-Policy", "default-src 'none'; img-src 'self'; style-src 'unsafe-inline'; sandbox");
1741
1830
  res.writeHead(ranged ? 206 : 200);
1742
1831
  res.end(got.bytes);
1743
1832
  }
@@ -1769,6 +1858,9 @@ function shellBodyTag(req, ctx, mode) {
1769
1858
  + ` data-usage-panel="${ctx.fleetConfig?.web?.usage_panel === false ? "0" : "1"}"`
1770
1859
  // #1218: whether the Log tab is on (web.log_tab; off by default): the tab says so and offers to turn it on.
1771
1860
  + ` data-log-tab="${ctx.fleetConfig?.web?.log_tab === true ? "1" : "0"}"`
1861
+ // #1937: the upload limits in force for this page (the config's; the public link's own cap on it) — what the chat
1862
+ // checks before sending a file, and the numbers its words say. The server checks again on every upload.
1863
+ + ` data-upload-limits="${attr(JSON.stringify(uploadLimits(ctx.fleetConfig?.web, { publicLink: gatewayRequestContext(req) !== undefined })))}"`
1772
1864
  // #1770: the fleet's zone (chat-logs' and fleet.log's), in which the chat reads its message times and days.
1773
1865
  + ` data-fleet-tz="${attr(resolveTz())}"`
1774
1866
  // #1589: the public link shows attachments as downloads only (no inline text or media): its scope is unchanged.