@mrgoonie/multix 1.0.1 → 1.0.2

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 CHANGED
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.0.2](https://github.com/mrgoonie/multix-cli/compare/v1.0.1...v1.0.2) (2026-10-11)
9
+
10
+
11
+ ### Fixed
12
+
13
+ * **fal:** only send the key to trusted queue status and response URLs ([#112](https://github.com/mrgoonie/multix-cli/issues/112)) ([92e61c5](https://github.com/mrgoonie/multix-cli/commit/92e61c547999e0bb30f1f4be6d9bbc1ce8226d24))
14
+
8
15
  ## [1.0.1](https://github.com/mrgoonie/multix-cli/compare/v1.0.0...v1.0.1) (2026-10-11)
9
16
 
10
17
 
package/dist/cli.js CHANGED
@@ -4520,6 +4520,7 @@ var FAL_DEFAULTS = {
4520
4520
  };
4521
4521
 
4522
4522
  // src/providers/fal/run-helpers.ts
4523
+ init_errors();
4523
4524
  import fs18 from "fs";
4524
4525
  import path21 from "path";
4525
4526
  init_redact();
@@ -4528,6 +4529,34 @@ init_redact();
4528
4529
  init_errors();
4529
4530
  init_errors();
4530
4531
  init_redact();
4532
+ var FAL_QUEUE_HOST = "queue.fal.run";
4533
+ function parseUrl(url) {
4534
+ try {
4535
+ return new URL(url);
4536
+ } catch {
4537
+ return void 0;
4538
+ }
4539
+ }
4540
+ function normalizedHost(u) {
4541
+ return u.hostname.toLowerCase().replace(/\.$/, "");
4542
+ }
4543
+ function normalizedOrigin(u) {
4544
+ return `${u.protocol}//${normalizedHost(u)}:${u.port}`;
4545
+ }
4546
+ function assertTrustedFalUrl(url, baseUrl) {
4547
+ const target = parseUrl(url);
4548
+ if (!target) {
4549
+ throw new ProviderError("Refusing to send the fal key to a malformed URL", "fal");
4550
+ }
4551
+ const base = parseUrl(baseUrl);
4552
+ if (base && normalizedOrigin(target) === normalizedOrigin(base)) return;
4553
+ const host = normalizedHost(target);
4554
+ if (target.protocol === "https:" && host === FAL_QUEUE_HOST && target.port === "") return;
4555
+ throw new ProviderError(
4556
+ `Refusing to send the fal key to ${host || "this URL"}: not https://${FAL_QUEUE_HOST} or the FAL_BASE_URL origin`,
4557
+ "fal"
4558
+ );
4559
+ }
4531
4560
  function requireFalKey() {
4532
4561
  const key = resolveRoutedKey(FAL_ROUTING);
4533
4562
  if (!key) {
@@ -4549,10 +4578,22 @@ var FalClient = class {
4549
4578
  async request(path57, opts = {}) {
4550
4579
  const base = this.baseUrl.replace(/\/$/, "");
4551
4580
  const suffix = path57.startsWith("/") ? path57 : `/${path57}`;
4552
- return this.requestAbsolute(base + suffix, opts);
4581
+ return this.send(base + suffix, opts);
4553
4582
  }
4554
- /** Same auth/headers as `request`, but `url` is used verbatim (e.g. a status_url/response_url returned by submit). */
4583
+ /**
4584
+ * Same auth/headers as `request`, but `url` is used verbatim (e.g. a
4585
+ * status_url/response_url returned by submit). The URL must pass
4586
+ * {@link assertTrustedFalUrl} before the key is sent.
4587
+ */
4555
4588
  async requestAbsolute(url, opts = {}) {
4589
+ assertTrustedFalUrl(url, this.baseUrl);
4590
+ return this.send(url, opts);
4591
+ }
4592
+ /** Throws a ProviderError when `url` may not receive the key (see {@link assertTrustedFalUrl}). */
4593
+ assertTrustedUrl(url) {
4594
+ assertTrustedFalUrl(url, this.baseUrl);
4595
+ }
4596
+ async send(url, opts) {
4556
4597
  opts.logger?.debug(`${opts.method ?? "GET"} ${redactUrl(url)}`);
4557
4598
  return httpJson({
4558
4599
  url,
@@ -4620,6 +4661,13 @@ async function submitAndWait(opts) {
4620
4661
  const submitRes = await client.post(submitPath(model), input, logger);
4621
4662
  const requestId = submitRes.request_id;
4622
4663
  logger.debug(`request_id: ${requestId}`);
4664
+ for (const field of ["status_url", "response_url"]) {
4665
+ const url = submitRes[field];
4666
+ if (typeof url !== "string" || url === "") {
4667
+ throw new ProviderError(`fal submit response is missing ${field}`, "fal");
4668
+ }
4669
+ client.assertTrustedUrl(url);
4670
+ }
4623
4671
  logger.info("Polling for completion...");
4624
4672
  const waitTimeoutMs = opts.waitTimeoutMs ?? 48e4;
4625
4673
  const intervalMs = opts.pollIntervalMs ?? 3e3;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrgoonie/multix",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "AI multimodal CLI — OpenAI, Gemini, MiniMax, OpenRouter, Leonardo, BytePlus, ElevenLabs, fal.ai, Atlas Cloud, Replicate, HeyGen, ffmpeg, ImageMagick, doc-to-md",
5
5
  "type": "module",
6
6
  "bin": {
package/skill/SKILL.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: multix
3
3
  description: AI multimodal CLI — generate and edit images (OpenAI, Codex driver, Gemini Nano Banana, Imagen, MiniMax, OpenRouter, Leonardo, BytePlus Seedream, Cloudflare Workers AI FLUX.1 Schnell, fal.ai FLUX, Replicate FLUX), generate video (Gemini Veo, MiniMax Hailuo, OpenRouter via Veo/Seedance/Kling, Leonardo via Motion/Veo/Kling/Hailuo/Seedance/LTX, BytePlus Seedance, Cloudflare AI Gateway via Replicate, fal.ai queue models, Replicate direct API models incl. P-Video, HeyGen Video Agent and scripted avatar videos), video translation and lipsync (HeyGen), TTS/STT/music (OpenAI, Gemini Flash TTS incl. Gemini 3.8 with delivery-style control, MiniMax, Cloudflare Workers AI MeloTTS, ElevenLabs), 3D models (BytePlus Hyper3D/Hitem3d), analyze/transcribe media, convert documents to Markdown, optimize media via ffmpeg/ImageMagick, and self-update the CLI. Use whenever the user wants to create, edit, or transform images/video/audio/3D/documents from a CLI, mentions any of: OpenAI, Codex image driver, image-to-image, i2i, image edit, watercolor/cyberpunk style transfer, reference image, OpenRouter, Nano Banana, Flux, Seedream, Veo, Hailuo, Seedance, Kling, Cloudflare Workers AI, AI Gateway, fal.ai, Atlas Cloud, Replicate, replicate.com models, Replicate predictions, HeyGen, avatar video, talking head, Video Agent, video translation, dubbing, lipsync, video generation, text-to-video, image-to-video, i2v, ElevenLabs voice cloning, updating/upgrading multix, or asks for batch media optimization.
4
- version: 1.0.1 # x-release-please-version
4
+ version: 1.0.2 # x-release-please-version
5
5
  ---
6
6
 
7
7
  # multix — AI Multimodal CLI