@langchain/langgraph-cli 1.5.4 → 1.5.6

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.
@@ -22,7 +22,7 @@ import { activeDockerHost } from "../docker/compose.mjs";
22
22
  import { DOCKER_NOT_INSTALLED, DOCKER_NOT_RUNNING, isBinaryNotFound, } from "../docker/errors.mjs";
23
23
  import { HostBackendClient, HostBackendError, } from "./utils/host-backend.mjs";
24
24
  import { Emitter, Spinner } from "./utils/deploy-output.mjs";
25
- import { createArchive, BYTES_PER_MIB } from "./utils/archive.mjs";
25
+ import { createArchive, BYTES_PER_MIB, MAX_SIZE } from "./utils/archive.mjs";
26
26
  import { API_KEY_ENV_NAMES, DEFAULT_HOST_URL, DEPLOYMENT_NAME_ENV, TERMINAL_STATUSES, envWithoutDeploymentName, findDeploymentIdByName, formatDeploymentsTable, formatLogEntry, formatRevisionsTable, getDeploymentStatusUrl, hasDisallowedBuildCommandContent, isPathWithin, levelColor, normalizeImageTag, normalizeName, resolvePushTarget, secretsFromEnv, smithDashboardBaseUrl, } from "./utils/deploy-helpers.mjs";
27
27
  // ---------------------------------------------------------------------------
28
28
  // Module-level state (mirrors the Python globals `_emitter` / `_no_input`).
@@ -516,7 +516,15 @@ async function resolvePushedImageDigest(opts, remoteImage) {
516
516
  // ---------------------------------------------------------------------------
517
517
  /** Chunk size used when streaming the source archive upload (1 MiB). */
518
518
  const UPLOAD_CHUNK_SIZE = 1024 * 1024;
519
- async function uploadToGcs(signedUrl, filePath, fileSize) {
519
+ /** Byte range Cloud Storage signs into upload URLs, up to the archive limit. */
520
+ const GCS_SIZE_RANGE = `0,${MAX_SIZE}`;
521
+ /** The string-valued entries of a control plane's `upload_headers`. */
522
+ function uploadHeadersFrom(value) {
523
+ if (!isPlainObject(value))
524
+ return {};
525
+ return Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[1] === "string"));
526
+ }
527
+ async function uploadSourceTarball(signedUrl, filePath, fileSize, uploadHeaders) {
520
528
  const sizeMb = fileSize / BYTES_PER_MIB;
521
529
  const handle = await fs.open(filePath, "r");
522
530
  let closed = false;
@@ -552,15 +560,21 @@ async function uploadToGcs(signedUrl, filePath, fileSize) {
552
560
  await closeHandle();
553
561
  },
554
562
  });
563
+ // Control planes that return no `upload_headers` sign for the Cloud Storage
564
+ // size range. Content-Type is a fallback, so both CLIs send one even when the
565
+ // control plane leaves it out.
566
+ const headers = new Headers({ "Content-Type": "application/gzip" });
567
+ const required = Object.keys(uploadHeaders).length
568
+ ? uploadHeaders
569
+ : { "X-Goog-Content-Length-Range": GCS_SIZE_RANGE };
570
+ for (const [name, value] of Object.entries(required))
571
+ headers.set(name, value);
572
+ headers.set("Content-Length", String(fileSize));
555
573
  try {
556
574
  // `duplex: "half"` is required by undici when sending a streaming body.
557
575
  const response = await fetch(signedUrl, {
558
576
  method: "PUT",
559
- headers: {
560
- "Content-Type": "application/gzip",
561
- "Content-Length": String(fileSize),
562
- "X-Goog-Content-Length-Range": "0,209715200",
563
- },
577
+ headers,
564
578
  body,
565
579
  duplex: "half",
566
580
  });
@@ -755,7 +769,7 @@ async function runRemoteBuild(args) {
755
769
  }
756
770
  step += 1;
757
771
  emitter.step(step, "Uploading source");
758
- await uploadToGcs(signedUrl, archive.archivePath, archive.fileSize);
772
+ await uploadSourceTarball(signedUrl, archive.archivePath, archive.fileSize, uploadHeadersFrom(uploadData.upload_headers));
759
773
  step += 1;
760
774
  emitter.step(step, "Triggering remote build");
761
775
  const updated = await args.client.updateDeploymentInternalSource(args.deploymentId, {
@@ -127,4 +127,4 @@ export async function createArchive(configPath, options = {}) {
127
127
  throw error;
128
128
  }
129
129
  }
130
- export { BYTES_PER_MIB };
130
+ export { BYTES_PER_MIB, MAX_SIZE };
@@ -222,14 +222,20 @@ export class HostBackendClient {
222
222
  });
223
223
  }
224
224
  /**
225
- * Request a signed GCS upload URL for the source tarball used by remote
226
- * builds (`POST /v2/deployments/{id}/upload-url`).
225
+ * Request a signed upload URL for the source tarball used by remote builds
226
+ * (`POST /v2/deployments/{id}/upload-url`).
227
+ *
228
+ * Tells the control plane this client sends the returned `upload_headers`
229
+ * with its upload, which some storage requires.
227
230
  *
228
231
  * @param deploymentId - Deployment ID.
229
- * @returns A response containing the `upload_url` and `object_path`.
232
+ * @returns A response containing the `upload_url` and `object_path`, plus
233
+ * `upload_headers` when the signed URL requires them.
230
234
  */
231
235
  requestUploadUrl(deploymentId) {
232
- return this.request("POST", `/v2/deployments/${deploymentId}/upload-url`);
236
+ return this.request("POST", `/v2/deployments/${deploymentId}/upload-url`, {
237
+ payload: { supports_upload_headers: true },
238
+ });
233
239
  }
234
240
  /**
235
241
  * Update a deployment to a new pre-built image, creating a new revision
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph-cli",
3
- "version": "1.5.4",
3
+ "version": "1.5.6",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": "^18.19.0 || >=20.16.0"
@@ -38,8 +38,8 @@
38
38
  "winston": "^3.17.0",
39
39
  "winston-console-format": "^1.0.8",
40
40
  "yaml": "^2.8.3",
41
- "zod": "^3.25.76 || ^4",
42
- "@langchain/langgraph-api": "1.5.4",
41
+ "zod": "^4.6.6",
42
+ "@langchain/langgraph-api": "1.5.6",
43
43
  "create-langgraph": "1.1.5"
44
44
  },
45
45
  "devDependencies": {
@@ -47,7 +47,7 @@
47
47
  "@types/node": "^18.15.11",
48
48
  "tsx": "^4.19.3",
49
49
  "typescript": "^4.9.5 || ^5.4.5",
50
- "vitest": "^4.1.11"
50
+ "vitest": "^4.1.12"
51
51
  },
52
52
  "scripts": {
53
53
  "clean": "rm -rf dist/ .turbo/",