dreamlayer 0.4.0-beta.2 → 0.4.0-beta.3

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/README.md CHANGED
@@ -167,3 +167,7 @@ retry the indicated recovery action, never blindly repeat a paid command.
167
167
  use `authentication_failed` (exit 2). A cancelled run uses `execution_cancelled`, exit 4,
168
168
  and a JSON error on stderr. Unknown client failures use `client_error`; they do not
169
169
  prove that the server-side generation failed.
170
+
171
+ ## Error handling updates in beta.3
172
+
173
+ Transport failures include a safe connection category without exposing URLs or credentials. Cancelled executions recommend a status check; download authentication failures retain exit code 2. Help flags are parsed as options so a literal `-h` option value is preserved.
package/dist/cli.js CHANGED
@@ -102,7 +102,9 @@ async function downloadOutput(api, url) {
102
102
  try {
103
103
  return await api.download(url);
104
104
  }
105
- catch {
105
+ catch (error) {
106
+ if (error instanceof ApiError && [401, 403].includes(error.status))
107
+ throw error;
106
108
  throw new CommandError("download_failed", "The completed output could not be downloaded.", 5, true, "Retry dreamlayer download with the saved execution_id. Do not generate again.");
107
109
  }
108
110
  }
@@ -116,11 +118,14 @@ function parseOptions(argv) {
116
118
  aspect: "1:1",
117
119
  json: false,
118
120
  quiet: false,
121
+ help: false,
119
122
  idempotencyKey: null,
120
123
  };
121
124
  for (let i = 0; i < argv.length; i += 1) {
122
125
  const token = argv[i];
123
- if (token === "--json")
126
+ if (token === "--help" || token === "-h")
127
+ options.help = true;
128
+ else if (token === "--json")
124
129
  options.json = true;
125
130
  else if (token === "--quiet")
126
131
  options.quiet = true;
@@ -317,15 +322,15 @@ async function main(argv) {
317
322
  process.stdout.write(USAGE);
318
323
  return command ? 0 : 1;
319
324
  }
320
- if (rest.includes("--help") || rest.includes("-h")) {
321
- process.stdout.write(USAGE);
322
- return 0;
323
- }
324
325
  if (command === "--version" || command === "-v") {
325
326
  process.stdout.write(`${PACKAGE_VERSION}\n`);
326
327
  return 0;
327
328
  }
328
329
  const { positional, options } = parseOptions(rest);
330
+ if (options.help) {
331
+ process.stdout.write(USAGE);
332
+ return 0;
333
+ }
329
334
  if (["generate", "edit", "cutout", "upscale", "sprite", "answer"].includes(command)) {
330
335
  options.out ??= command === "sprite" ? `dreamlayer-${Date.now()}.zip` : defaultOut();
331
336
  await preflightOutput(options.out);
@@ -441,7 +446,7 @@ main(process.argv.slice(2))
441
446
  const known = error instanceof CommandError ? error : error instanceof InputValidationError
442
447
  ? new CommandError("invalid_request", error.message, 1)
443
448
  : error instanceof RecoveryRequiredError
444
- ? new CommandError("temporarily_unavailable", "Execution state is uncertain. Read saved state before retrying.", 5, true, "Use status and download for the saved execution. If no ID was received, replay identical inputs with the original idempotency key.") : null;
449
+ ? new CommandError("temporarily_unavailable", error.message, 5, true, "Use status and download for the saved execution. If no ID was received, replay identical inputs with the original idempotency key.") : null;
445
450
  if (known) {
446
451
  const partial = error.partialOutcome;
447
452
  const identity = { ...recovery, ...(partial?.execution_id ? { execution_id: partial.execution_id } : {}) };
@@ -449,9 +454,12 @@ main(process.argv.slice(2))
449
454
  if (process.argv.slice(2).includes("--json"))
450
455
  process.stderr.write(`${JSON.stringify(envelope)}\n`);
451
456
  else {
452
- process.stderr.write(`${known.message}\n${known.guidance ?? ""}\n`);
453
- if (identity.execution_id)
454
- process.stderr.write(`Execution: ${identity.execution_id}\n dreamlayer status ${identity.execution_id}\n dreamlayer download ${identity.execution_id} --out <new-file>\n`);
457
+ process.stderr.write(`${known.message}\n${known.guidance ? known.guidance + "\n" : ""}`);
458
+ if (identity.execution_id) {
459
+ process.stderr.write(`Execution: ${identity.execution_id}\n dreamlayer status ${identity.execution_id}\n`);
460
+ if (["local_output_failed", "download_failed"].includes(known.reason))
461
+ process.stderr.write(` dreamlayer download ${identity.execution_id} --out <new-file>\n`);
462
+ }
455
463
  if (identity.idempotency_key)
456
464
  process.stderr.write(`Idempotency key: ${identity.idempotency_key}\n`);
457
465
  }
@@ -482,12 +490,7 @@ main(process.argv.slice(2))
482
490
  : error.retryable
483
491
  ? "Temporary. Retry with --idempotency-key to avoid paying twice."
484
492
  : "";
485
- if (process.argv.slice(2).includes("--json")) {
486
- process.stderr.write(`${JSON.stringify(error.toPublicEnvelope())}\n`);
487
- }
488
- else {
489
- process.stderr.write(`${error.message}\nReason: ${error.reason}${hint ? `\n${hint}` : ""}\n`);
490
- }
493
+ process.stderr.write(`${error.message}\nReason: ${error.reason}${hint ? `\n${hint}` : ""}\n`);
491
494
  process.exitCode = exitCodeFor(error);
492
495
  return;
493
496
  }
package/dist/client.js CHANGED
@@ -491,8 +491,16 @@ export class ManagedClient {
491
491
  throw error;
492
492
  if (!executionId && error instanceof ApiError)
493
493
  throw error;
494
- if (!executionId || ++failures > 5)
495
- throw new RecoveryRequiredError("Execution state is uncertain. Read saved state before retrying.");
494
+ if (!executionId || ++failures > 5) {
495
+ const code = error?.cause?.code ?? error?.code;
496
+ const causes = {
497
+ ECONNREFUSED: "Connection refused", ENOTFOUND: "Host lookup failed", EAI_AGAIN: "Host lookup temporarily failed",
498
+ ECONNRESET: "Connection reset", ETIMEDOUT: "Connection timed out", UND_ERR_CONNECT_TIMEOUT: "Connection timed out",
499
+ UND_ERR_SOCKET: "Connection closed", CERT_HAS_EXPIRED: "TLS certificate expired", DEPTH_ZERO_SELF_SIGNED_CERT: "TLS certificate is untrusted",
500
+ };
501
+ const cause = code && causes[code] ? `${causes[code]} (${code}). ` : "Transport connection failed. ";
502
+ throw new RecoveryRequiredError(cause + "Execution state is uncertain. Read saved state before retrying.");
503
+ }
496
504
  }
497
505
  if (!executionId)
498
506
  throw new RecoveryRequiredError("Execution stream ended before an identifier was received; reuse your idempotency key.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dreamlayer",
3
- "version": "0.4.0-beta.2",
3
+ "version": "0.4.0-beta.3",
4
4
  "description": "Generate and edit images from your terminal, over local files, with one API key.",
5
5
  "license": "MIT",
6
6
  "type": "module",