You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by co...@apache.org on 2026/03/22 03:08:31 UTC

(tinkerpop) branch js-interceptors updated (4ac71c7a91 -> 1093638a8d)

This is an automated email from the ASF dual-hosted git repository.

colegreer pushed a change to branch js-interceptors
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


 discard 4ac71c7a91 WIP add SigV4 auth interceptor
     new 500bbd7858 Add SigV4 auth interceptor
     new 1093638a8d Remove mimeType configuration in favour of reader and writer options, make writer optional.

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (4ac71c7a91)
            \
             N -- N -- N   refs/heads/js-interceptors (1093638a8d)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 CHANGELOG.asciidoc                                 |  1 +
 gremlin-javascript/examples/node/connections.js    |  1 -
 .../gremlin-javascript/lib/driver/client.ts        |  1 -
 .../gremlin-javascript/lib/driver/connection.ts    | 48 +++++++++-------------
 .../lib/driver/driver-remote-connection.ts         |  1 -
 .../io/binary/internals/GraphBinaryReader.js       |  4 ++
 .../io/binary/internals/GraphBinaryWriter.js       |  8 +++-
 .../javascript/gremlin-javascript/test/helper.js   | 40 ++----------------
 .../gremlin-javascript/test/unit/auth-test.js      | 10 ++---
 .../gremlin-javascript/test/unit/client-test.js    | 10 -----
 10 files changed, 37 insertions(+), 87 deletions(-)


(tinkerpop) 01/02: Add SigV4 auth interceptor

Posted by co...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

colegreer pushed a commit to branch js-interceptors
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 500bbd78581cca53820934d5e28156715eeba555
Author: Cole Greer <Co...@improving.com>
AuthorDate: Sat Mar 21 18:56:40 2026 -0700

    Add SigV4 auth interceptor
---
 .../gremlin-javascript/lib/driver/auth.ts          |   81 ++
 .../gremlin-javascript/lib/driver/client.ts        |    1 +
 .../gremlin-javascript/lib/driver/connection.ts    |   38 +-
 .../lib/driver/driver-remote-connection.ts         |    1 +
 .../javascript/gremlin-javascript/lib/index.ts     |    5 +-
 .../gremlin-javascript/package-lock.json           | 1322 +++++++++++++++++++-
 .../javascript/gremlin-javascript/package.json     |    7 +-
 .../javascript/gremlin-javascript/test/helper.js   |   18 +
 .../test/integration/auth-tests.js                 |   81 ++
 .../gremlin-javascript/test/unit/auth-test.js      |  124 ++
 .../gremlin-javascript/test/unit/exports-test.js   |    2 +
 11 files changed, 1670 insertions(+), 10 deletions(-)

diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/auth.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/auth.ts
new file mode 100644
index 0000000000..41f5573b27
--- /dev/null
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/auth.ts
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+import { Buffer } from 'buffer';
+import type { HttpRequest, RequestInterceptor } from './connection.js';
+
+export function basic(username: string, password: string): RequestInterceptor {
+  return (request: HttpRequest) => {
+    request.headers['authorization'] = 'Basic ' + Buffer.from(`${username}:${password}`).toString('base64');
+    return request;
+  };
+}
+
+export interface AwsCredentials {
+  accessKeyId: string;
+  secretAccessKey: string;
+  sessionToken?: string;
+}
+
+export type AwsCredentialsProvider = () => AwsCredentials | Promise<AwsCredentials>;
+
+export function sigv4(region: string, service: string, credentialsProvider?: AwsCredentialsProvider): RequestInterceptor {
+  let signer: any;
+  let resolvedProvider: AwsCredentialsProvider;
+
+  return async (request: HttpRequest) => {
+    // Lazy-initialize signer and credentials provider on first use
+    if (!signer) {
+      const { SignatureV4 } = await import('@smithy/signature-v4');
+      const { Hash } = await import('@smithy/hash-node');
+
+      if (credentialsProvider) {
+        resolvedProvider = credentialsProvider;
+      } else {
+        const { fromNodeProviderChain } = await import('@aws-sdk/credential-providers');
+        const chain = fromNodeProviderChain({ clientConfig: { region } });
+        resolvedProvider = () => chain();
+      }
+
+      signer = new SignatureV4({
+        service,
+        region,
+        sha256: Hash.bind(null, 'sha256'),
+        credentials: () => Promise.resolve(resolvedProvider()),
+      });
+    }
+
+    const url = new URL(request.url);
+    const signed = await signer.sign({
+      method: request.method,
+      protocol: url.protocol,
+      hostname: url.hostname,
+      port: url.port ? Number(url.port) : undefined,
+      path: url.pathname + url.search,
+      headers: {
+        ...request.headers,
+        host: url.host,
+      },
+      body: request.body,
+    });
+
+    request.headers = signed.headers;
+    return request;
+  };
+}
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.ts
index 71c25905f8..a74c0081c9 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.ts
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.ts
@@ -59,6 +59,7 @@ export default class Client {
    * @param {String} [options.processor] The name of the opProcessor to use, leave it undefined or set 'session' when session mode.
    * @param {String} [options.session] The sessionId of Client in session mode. Defaults to null means session-less Client.
    * @param {http.Agent} [options.agent] The http.Agent implementation to use.
+   * @param {RequestInterceptor|RequestInterceptor[]} [options.interceptors] One or more request interceptors to apply before each HTTP request.
    * @constructor
    */
   constructor(
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.ts
index 4232368759..1e2b1d1560 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.ts
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.ts
@@ -47,6 +47,15 @@ const graphBinaryMimeType = 'application/vnd.graphbinary-v4.0';
 
 type MimeType = typeof defaultMimeType | typeof graphBinaryMimeType;
 
+export type HttpRequest = {
+  url: string;
+  method: string;
+  headers: Record<string, string>;
+  body: Uint8Array;
+};
+
+export type RequestInterceptor = (request: HttpRequest) => HttpRequest | Promise<HttpRequest>;
+
 export type ConnectionOptions = {
   ca?: string[];
   cert?: string | string[] | Buffer;
@@ -59,6 +68,7 @@ export type ConnectionOptions = {
   headers?: Record<string, string | string[]>;
   enableUserAgentOnConnect?: boolean;
   agent?: Agent;
+  interceptors?: RequestInterceptor | RequestInterceptor[];
 };
 
 /**
@@ -74,6 +84,7 @@ export default class Connection extends EventEmitter {
   traversalSource: string;
 
   private readonly _enableUserAgentOnConnect: boolean;
+  private readonly _interceptors: RequestInterceptor[];
 
   /**
    * Creates a new instance of {@link Connection}.
@@ -90,6 +101,7 @@ export default class Connection extends EventEmitter {
    * @param {Object} [options.headers] An associative array containing the additional header key/values for the initial request.
    * @param {Boolean} [options.enableUserAgentOnConnect] Determines if a user agent will be sent during connection handshake. Defaults to: true
    * @param {http.Agent} [options.agent] The http.Agent implementation to use.
+   * @param {RequestInterceptor|RequestInterceptor[]} [options.interceptors] One or more request interceptors to apply before each HTTP request.
    * @constructor
    */
   constructor(
@@ -107,6 +119,17 @@ export default class Connection extends EventEmitter {
     this._writer = options.writer || graphBinaryWriter;
     this.traversalSource = options.traversalSource || 'g';
     this._enableUserAgentOnConnect = options.enableUserAgentOnConnect !== false;
+
+    const interceptors = options.interceptors;
+    if (typeof interceptors === 'function') {
+      this._interceptors = [interceptors];
+    } else if (Array.isArray(interceptors)) {
+      this._interceptors = interceptors;
+    } else if (interceptors === undefined || interceptors === null) {
+      this._interceptors = [];
+    } else {
+      throw new TypeError('interceptors must be a function, array, or undefined');
+    }
   }
 
   /**
@@ -163,15 +186,22 @@ export default class Connection extends EventEmitter {
         headers[key] = Array.isArray(value) ? value.join(', ') : value;
       });
     }
-    let request = {
+    let httpRequest: HttpRequest = {
+      url: this.url,
       method: 'POST',
       headers,
       body: new Uint8Array(request_buf),
-    }
+    };
 
-    // TODO:: add request interceptors
+    for (const interceptor of this._interceptors) {
+      httpRequest = await interceptor(httpRequest);
+    }
 
-    return fetch(this.url, request);
+    return fetch(httpRequest.url, {
+      method: httpRequest.method,
+      headers: httpRequest.headers,
+      body: httpRequest.body as BodyInit,
+    });
   }
 
   async #handleResponse(response: Response) {
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.ts
index bed6231980..ad9dd8b4cf 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.ts
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.ts
@@ -51,6 +51,7 @@ export default class DriverRemoteConnection extends RemoteConnection {
    * @param {Object} [options.headers] An associative array containing the additional header key/values for the initial request.
    * @param {Boolean} [options.enableUserAgentOnConnect] Determines if a user agent will be sent during connection handshake. Defaults to: true
    * @param {http.Agent} [options.agent] The http.Agent implementation to use.
+   * @param {RequestInterceptor|RequestInterceptor[]} [options.interceptors] One or more request interceptors to apply before each HTTP request.
    * @constructor
    */
   constructor(url: string, options: ConnectionOptions = {}) {
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/index.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/index.ts
index ad8e26dbf8..b0d47a306f 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/index.ts
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/index.ts
@@ -32,7 +32,7 @@ import DriverRemoteConnection from './driver/driver-remote-connection.js';
 import ResponseError from './driver/response-error.js';
 import Client from './driver/client.js';
 import ResultSet from './driver/result-set.js';
-import Authenticator from './driver/auth/authenticator.js';
+import { basic, sigv4 } from './driver/auth.js';
 import AnonymousTraversalSource from './process/anonymous-traversal.js';
 
 export const driver = {
@@ -44,7 +44,8 @@ export const driver = {
   Client,
   ResultSet,
   auth: {
-    Authenticator,
+    basic,
+    sigv4,
   },
 };
 
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/package-lock.json b/gremlin-javascript/src/main/javascript/gremlin-javascript/package-lock.json
index 1800f2e6d1..cc1c9c73ea 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/package-lock.json
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/package-lock.json
@@ -9,6 +9,9 @@
       "version": "4.0.0-alpha1",
       "license": "Apache-2.0",
       "dependencies": {
+        "@aws-sdk/credential-providers": "^3.967.0",
+        "@smithy/hash-node": "^4.2.12",
+        "@smithy/signature-v4": "^5.3.12",
         "buffer": "^6.0.3",
         "eventemitter3": "^5.0.1",
         "readable-stream": "^4.5.2",
@@ -40,6 +43,705 @@
         "node": ">=20"
       }
     },
+    "node_modules/@aws-crypto/sha256-browser": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz",
+      "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-crypto/sha256-js": "^5.2.0",
+        "@aws-crypto/supports-web-crypto": "^5.2.0",
+        "@aws-crypto/util": "^5.2.0",
+        "@aws-sdk/types": "^3.222.0",
+        "@aws-sdk/util-locate-window": "^3.0.0",
+        "@smithy/util-utf8": "^2.0.0",
+        "tslib": "^2.6.2"
+      }
+    },
+    "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz",
+      "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz",
+      "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/is-array-buffer": "^2.2.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz",
+      "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/util-buffer-from": "^2.2.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@aws-crypto/sha256-js": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz",
+      "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-crypto/util": "^5.2.0",
+        "@aws-sdk/types": "^3.222.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
+    "node_modules/@aws-crypto/supports-web-crypto": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz",
+      "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.6.2"
+      }
+    },
+    "node_modules/@aws-crypto/util": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz",
+      "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/types": "^3.222.0",
+        "@smithy/util-utf8": "^2.0.0",
+        "tslib": "^2.6.2"
+      }
+    },
+    "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz",
+      "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz",
+      "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/is-array-buffer": "^2.2.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz",
+      "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/util-buffer-from": "^2.2.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/client-cognito-identity": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.967.0.tgz",
+      "integrity": "sha512-nVC/GpKTkBm9+lCZl40DbzBuqJIi5tJosZHSjnc7GavRJOZvFIX8XE5db81+zi+FqVTDrhPPaKpdAeoE9qYHAw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-crypto/sha256-browser": "5.2.0",
+        "@aws-crypto/sha256-js": "5.2.0",
+        "@aws-sdk/core": "3.967.0",
+        "@aws-sdk/credential-provider-node": "3.967.0",
+        "@aws-sdk/middleware-host-header": "3.965.0",
+        "@aws-sdk/middleware-logger": "3.965.0",
+        "@aws-sdk/middleware-recursion-detection": "3.965.0",
+        "@aws-sdk/middleware-user-agent": "3.967.0",
+        "@aws-sdk/region-config-resolver": "3.965.0",
+        "@aws-sdk/types": "3.965.0",
+        "@aws-sdk/util-endpoints": "3.965.0",
+        "@aws-sdk/util-user-agent-browser": "3.965.0",
+        "@aws-sdk/util-user-agent-node": "3.967.0",
+        "@smithy/config-resolver": "^4.4.5",
+        "@smithy/core": "^3.20.2",
+        "@smithy/fetch-http-handler": "^5.3.8",
+        "@smithy/hash-node": "^4.2.7",
+        "@smithy/invalid-dependency": "^4.2.7",
+        "@smithy/middleware-content-length": "^4.2.7",
+        "@smithy/middleware-endpoint": "^4.4.3",
+        "@smithy/middleware-retry": "^4.4.19",
+        "@smithy/middleware-serde": "^4.2.8",
+        "@smithy/middleware-stack": "^4.2.7",
+        "@smithy/node-config-provider": "^4.3.7",
+        "@smithy/node-http-handler": "^4.4.7",
+        "@smithy/protocol-http": "^5.3.7",
+        "@smithy/smithy-client": "^4.10.4",
+        "@smithy/types": "^4.11.0",
+        "@smithy/url-parser": "^4.2.7",
+        "@smithy/util-base64": "^4.3.0",
+        "@smithy/util-body-length-browser": "^4.2.0",
+        "@smithy/util-body-length-node": "^4.2.1",
+        "@smithy/util-defaults-mode-browser": "^4.3.18",
+        "@smithy/util-defaults-mode-node": "^4.2.21",
+        "@smithy/util-endpoints": "^3.2.7",
+        "@smithy/util-middleware": "^4.2.7",
+        "@smithy/util-retry": "^4.2.7",
+        "@smithy/util-utf8": "^4.2.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/client-sso": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.967.0.tgz",
+      "integrity": "sha512-7RgUwHcRMJtWme6kCHGUVT+Rn9GmNH+FHm34N9UgMXzUqQlzFMweE7T5E9O8nv3wIp7xFNB20ADaCw9Xdnox1Q==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-crypto/sha256-browser": "5.2.0",
+        "@aws-crypto/sha256-js": "5.2.0",
+        "@aws-sdk/core": "3.967.0",
+        "@aws-sdk/middleware-host-header": "3.965.0",
+        "@aws-sdk/middleware-logger": "3.965.0",
+        "@aws-sdk/middleware-recursion-detection": "3.965.0",
+        "@aws-sdk/middleware-user-agent": "3.967.0",
+        "@aws-sdk/region-config-resolver": "3.965.0",
+        "@aws-sdk/types": "3.965.0",
+        "@aws-sdk/util-endpoints": "3.965.0",
+        "@aws-sdk/util-user-agent-browser": "3.965.0",
+        "@aws-sdk/util-user-agent-node": "3.967.0",
+        "@smithy/config-resolver": "^4.4.5",
+        "@smithy/core": "^3.20.2",
+        "@smithy/fetch-http-handler": "^5.3.8",
+        "@smithy/hash-node": "^4.2.7",
+        "@smithy/invalid-dependency": "^4.2.7",
+        "@smithy/middleware-content-length": "^4.2.7",
+        "@smithy/middleware-endpoint": "^4.4.3",
+        "@smithy/middleware-retry": "^4.4.19",
+        "@smithy/middleware-serde": "^4.2.8",
+        "@smithy/middleware-stack": "^4.2.7",
+        "@smithy/node-config-provider": "^4.3.7",
+        "@smithy/node-http-handler": "^4.4.7",
+        "@smithy/protocol-http": "^5.3.7",
+        "@smithy/smithy-client": "^4.10.4",
+        "@smithy/types": "^4.11.0",
+        "@smithy/url-parser": "^4.2.7",
+        "@smithy/util-base64": "^4.3.0",
+        "@smithy/util-body-length-browser": "^4.2.0",
+        "@smithy/util-body-length-node": "^4.2.1",
+        "@smithy/util-defaults-mode-browser": "^4.3.18",
+        "@smithy/util-defaults-mode-node": "^4.2.21",
+        "@smithy/util-endpoints": "^3.2.7",
+        "@smithy/util-middleware": "^4.2.7",
+        "@smithy/util-retry": "^4.2.7",
+        "@smithy/util-utf8": "^4.2.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/core": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.967.0.tgz",
+      "integrity": "sha512-sJmuP7GrVmlbO6DpXkuf9Mbn6jGNNvy6PLawvaxVF150c8bpNk3w39rerRls6q1dot1dBFV2D29hBXMY1agNMg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/types": "3.965.0",
+        "@aws-sdk/xml-builder": "3.965.0",
+        "@smithy/core": "^3.20.2",
+        "@smithy/node-config-provider": "^4.3.7",
+        "@smithy/property-provider": "^4.2.7",
+        "@smithy/protocol-http": "^5.3.7",
+        "@smithy/signature-v4": "^5.3.7",
+        "@smithy/smithy-client": "^4.10.4",
+        "@smithy/types": "^4.11.0",
+        "@smithy/util-base64": "^4.3.0",
+        "@smithy/util-middleware": "^4.2.7",
+        "@smithy/util-utf8": "^4.2.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/credential-provider-cognito-identity": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.967.0.tgz",
+      "integrity": "sha512-kps8eC/ARt1f40ZJO4yCiFvhESLZ7zI2i1HMyNvA2f2mBmYszaqyAZoFwr7pBbqTuLmL4NWNcakONBOhho+6RA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/client-cognito-identity": "3.967.0",
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/property-provider": "^4.2.7",
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/credential-provider-env": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.967.0.tgz",
+      "integrity": "sha512-+XWw0+f/txeMbEVRtTFZhgSw1ymH1ffaVKkdMBSnw48rfSohJElKmitCqdihagRTZpzh7m8qI6tIQ5t3OUqugw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/core": "3.967.0",
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/property-provider": "^4.2.7",
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/credential-provider-http": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.967.0.tgz",
+      "integrity": "sha512-0/GIAEv5pY5htg6IBMuYccBgzz3oS2DqHjHi396ziTrwlhbrCNX96AbNhQhzAx3LBZUk13sPfeapjyQ7G57Ekg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/core": "3.967.0",
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/fetch-http-handler": "^5.3.8",
+        "@smithy/node-http-handler": "^4.4.7",
+        "@smithy/property-provider": "^4.2.7",
+        "@smithy/protocol-http": "^5.3.7",
+        "@smithy/smithy-client": "^4.10.4",
+        "@smithy/types": "^4.11.0",
+        "@smithy/util-stream": "^4.5.8",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/credential-provider-ini": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.967.0.tgz",
+      "integrity": "sha512-U8dMpaM6Qf6+2Qvp1uG6OcWv1RlrZW7tQkpmzEVWH8HZTGrVHIXXju64NMtIOr7yOnNwd0CKcytuD1QG+phCwQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/core": "3.967.0",
+        "@aws-sdk/credential-provider-env": "3.967.0",
+        "@aws-sdk/credential-provider-http": "3.967.0",
+        "@aws-sdk/credential-provider-login": "3.967.0",
+        "@aws-sdk/credential-provider-process": "3.967.0",
+        "@aws-sdk/credential-provider-sso": "3.967.0",
+        "@aws-sdk/credential-provider-web-identity": "3.967.0",
+        "@aws-sdk/nested-clients": "3.967.0",
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/credential-provider-imds": "^4.2.7",
+        "@smithy/property-provider": "^4.2.7",
+        "@smithy/shared-ini-file-loader": "^4.4.2",
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/credential-provider-login": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.967.0.tgz",
+      "integrity": "sha512-kbvZsZL6CBlfnb71zuJdJmBUFZN5utNrcziZr/DZ2olEOkA9vlmizE8i9BUIbmS7ptjgvRnmcY1A966yfhiblw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/core": "3.967.0",
+        "@aws-sdk/nested-clients": "3.967.0",
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/property-provider": "^4.2.7",
+        "@smithy/protocol-http": "^5.3.7",
+        "@smithy/shared-ini-file-loader": "^4.4.2",
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/credential-provider-node": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.967.0.tgz",
+      "integrity": "sha512-WuNbHs9rfKKSVok4+OBrZf0AHfzDgFYYMxN2G/q6ZfUmY4QmiPyxV5HkNFh1rqDxS9VV6kAZPo0EBmry10idSg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/credential-provider-env": "3.967.0",
+        "@aws-sdk/credential-provider-http": "3.967.0",
+        "@aws-sdk/credential-provider-ini": "3.967.0",
+        "@aws-sdk/credential-provider-process": "3.967.0",
+        "@aws-sdk/credential-provider-sso": "3.967.0",
+        "@aws-sdk/credential-provider-web-identity": "3.967.0",
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/credential-provider-imds": "^4.2.7",
+        "@smithy/property-provider": "^4.2.7",
+        "@smithy/shared-ini-file-loader": "^4.4.2",
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/credential-provider-process": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.967.0.tgz",
+      "integrity": "sha512-sNCY5JDV0whsfsZ6c2+6eUwH33H7UhKbqvCPbEYlIIa8wkGjCtCyFI3zZIJHVcMKJJ3117vSUFHEkNA7g+8rtw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/core": "3.967.0",
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/property-provider": "^4.2.7",
+        "@smithy/shared-ini-file-loader": "^4.4.2",
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/credential-provider-sso": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.967.0.tgz",
+      "integrity": "sha512-0K6kITKNytFjk1UYabYUsTThgU6TQkyW6Wmt8S5zd1A/up7NSQGpp58Rpg9GIf4amQDQwb+p9FGG7emmV8FEeA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/client-sso": "3.967.0",
+        "@aws-sdk/core": "3.967.0",
+        "@aws-sdk/token-providers": "3.967.0",
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/property-provider": "^4.2.7",
+        "@smithy/shared-ini-file-loader": "^4.4.2",
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/credential-provider-web-identity": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.967.0.tgz",
+      "integrity": "sha512-Vkr7S2ec7q/v8i/MzkHcBEdqqfWz3lyb8FDjb+NjslEwdxC3f6XwADRZzWwV1pChfx6SbsvJXKfkcF/pKAelhA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/core": "3.967.0",
+        "@aws-sdk/nested-clients": "3.967.0",
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/property-provider": "^4.2.7",
+        "@smithy/shared-ini-file-loader": "^4.4.2",
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/credential-providers": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.967.0.tgz",
+      "integrity": "sha512-AvpnwjzRw+R1XU5cqb5sIgK6zqounXCa41wXTK158oQQSDIxfEvghOZ43Mk8K9lpdpfJ9fWMW7kESqzUGzgn3A==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/client-cognito-identity": "3.967.0",
+        "@aws-sdk/core": "3.967.0",
+        "@aws-sdk/credential-provider-cognito-identity": "3.967.0",
+        "@aws-sdk/credential-provider-env": "3.967.0",
+        "@aws-sdk/credential-provider-http": "3.967.0",
+        "@aws-sdk/credential-provider-ini": "3.967.0",
+        "@aws-sdk/credential-provider-login": "3.967.0",
+        "@aws-sdk/credential-provider-node": "3.967.0",
+        "@aws-sdk/credential-provider-process": "3.967.0",
+        "@aws-sdk/credential-provider-sso": "3.967.0",
+        "@aws-sdk/credential-provider-web-identity": "3.967.0",
+        "@aws-sdk/nested-clients": "3.967.0",
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/config-resolver": "^4.4.5",
+        "@smithy/core": "^3.20.2",
+        "@smithy/credential-provider-imds": "^4.2.7",
+        "@smithy/node-config-provider": "^4.3.7",
+        "@smithy/property-provider": "^4.2.7",
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/middleware-host-header": {
+      "version": "3.965.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.965.0.tgz",
+      "integrity": "sha512-SfpSYqoPOAmdb3DBsnNsZ0vix+1VAtkUkzXM79JL3R5IfacpyKE2zytOgVAQx/FjhhlpSTwuXd+LRhUEVb3MaA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/protocol-http": "^5.3.7",
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/middleware-logger": {
+      "version": "3.965.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.965.0.tgz",
+      "integrity": "sha512-gjUvJRZT1bUABKewnvkj51LAynFrfz2h5DYAg5/2F4Utx6UOGByTSr9Rq8JCLbURvvzAbCtcMkkIJRxw+8Zuzw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/middleware-recursion-detection": {
+      "version": "3.965.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.965.0.tgz",
+      "integrity": "sha512-6dvD+18Ni14KCRu+tfEoNxq1sIGVp9tvoZDZ7aMvpnA7mDXuRLrOjRQ/TAZqXwr9ENKVGyxcPl0cRK8jk1YWjA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/types": "3.965.0",
+        "@aws/lambda-invoke-store": "^0.2.2",
+        "@smithy/protocol-http": "^5.3.7",
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/middleware-user-agent": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.967.0.tgz",
+      "integrity": "sha512-2qzJzZj5u+cZiG7kz3XJPaTH4ssUY/aet1kwJsUTFKrWeHUf7mZZkDFfkXP5cOffgiOyR5ZkrmJoLKAde9hshg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/core": "3.967.0",
+        "@aws-sdk/types": "3.965.0",
+        "@aws-sdk/util-endpoints": "3.965.0",
+        "@smithy/core": "^3.20.2",
+        "@smithy/protocol-http": "^5.3.7",
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/nested-clients": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.967.0.tgz",
+      "integrity": "sha512-PYa7V8w0gaNux6Sz/Z7zrHmPloEE+EKpRxQIOG/D0askTr5Yd4oO2KGgcInf65uHK3f0Z9U4CTUGHZvQvABypA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-crypto/sha256-browser": "5.2.0",
+        "@aws-crypto/sha256-js": "5.2.0",
+        "@aws-sdk/core": "3.967.0",
+        "@aws-sdk/middleware-host-header": "3.965.0",
+        "@aws-sdk/middleware-logger": "3.965.0",
+        "@aws-sdk/middleware-recursion-detection": "3.965.0",
+        "@aws-sdk/middleware-user-agent": "3.967.0",
+        "@aws-sdk/region-config-resolver": "3.965.0",
+        "@aws-sdk/types": "3.965.0",
+        "@aws-sdk/util-endpoints": "3.965.0",
+        "@aws-sdk/util-user-agent-browser": "3.965.0",
+        "@aws-sdk/util-user-agent-node": "3.967.0",
+        "@smithy/config-resolver": "^4.4.5",
+        "@smithy/core": "^3.20.2",
+        "@smithy/fetch-http-handler": "^5.3.8",
+        "@smithy/hash-node": "^4.2.7",
+        "@smithy/invalid-dependency": "^4.2.7",
+        "@smithy/middleware-content-length": "^4.2.7",
+        "@smithy/middleware-endpoint": "^4.4.3",
+        "@smithy/middleware-retry": "^4.4.19",
+        "@smithy/middleware-serde": "^4.2.8",
+        "@smithy/middleware-stack": "^4.2.7",
+        "@smithy/node-config-provider": "^4.3.7",
+        "@smithy/node-http-handler": "^4.4.7",
+        "@smithy/protocol-http": "^5.3.7",
+        "@smithy/smithy-client": "^4.10.4",
+        "@smithy/types": "^4.11.0",
+        "@smithy/url-parser": "^4.2.7",
+        "@smithy/util-base64": "^4.3.0",
+        "@smithy/util-body-length-browser": "^4.2.0",
+        "@smithy/util-body-length-node": "^4.2.1",
+        "@smithy/util-defaults-mode-browser": "^4.3.18",
+        "@smithy/util-defaults-mode-node": "^4.2.21",
+        "@smithy/util-endpoints": "^3.2.7",
+        "@smithy/util-middleware": "^4.2.7",
+        "@smithy/util-retry": "^4.2.7",
+        "@smithy/util-utf8": "^4.2.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/region-config-resolver": {
+      "version": "3.965.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.965.0.tgz",
+      "integrity": "sha512-RoMhu9ly2B0coxn8ctXosPP2WmDD0MkQlZGLjoYHQUOCBmty5qmCxOqBmBDa6wbWbB8xKtMQ/4VXloQOgzjHXg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/config-resolver": "^4.4.5",
+        "@smithy/node-config-provider": "^4.3.7",
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/token-providers": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.967.0.tgz",
+      "integrity": "sha512-Qnd/nJ0CgeUa7zQczgmdQm0vYUF7pD1G0C+dR1T7huHQHRIsgCWIsCV9wNKzOFluqtcr6YAeuTwvY0+l8XWxnA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/core": "3.967.0",
+        "@aws-sdk/nested-clients": "3.967.0",
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/property-provider": "^4.2.7",
+        "@smithy/shared-ini-file-loader": "^4.4.2",
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/types": {
+      "version": "3.965.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.965.0.tgz",
+      "integrity": "sha512-jvodoJdMavvg8faN7co58vVJRO5MVep4JFPRzUNCzpJ98BDqWDk/ad045aMJcmxkLzYLS2UAnUmqjJ/tUPNlzQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/util-endpoints": {
+      "version": "3.965.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.965.0.tgz",
+      "integrity": "sha512-WqSCB0XIsGUwZWvrYkuoofi2vzoVHqyeJ2kN+WyoOsxPLTiQSBIoqm/01R/qJvoxwK/gOOF7su9i84Vw2NQQpQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/types": "^4.11.0",
+        "@smithy/url-parser": "^4.2.7",
+        "@smithy/util-endpoints": "^3.2.7",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/util-locate-window": {
+      "version": "3.965.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.0.tgz",
+      "integrity": "sha512-9LJFand4bIoOjOF4x3wx0UZYiFZRo4oUauxQSiEX2dVg+5qeBOJSjp2SeWykIE6+6frCZ5wvWm2fGLK8D32aJw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws-sdk/util-user-agent-browser": {
+      "version": "3.965.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.965.0.tgz",
+      "integrity": "sha512-Xiza/zMntQGpkd2dETQeAK8So1pg5+STTzpcdGWxj5q0jGO5ayjqT/q1Q7BrsX5KIr6PvRkl9/V7lLCv04wGjQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/types": "^4.11.0",
+        "bowser": "^2.11.0",
+        "tslib": "^2.6.2"
+      }
+    },
+    "node_modules/@aws-sdk/util-user-agent-node": {
+      "version": "3.967.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.967.0.tgz",
+      "integrity": "sha512-yUz6pCGxyG4+QaDg0dkdIBphjQp8A9rrbZa/+U3RJgRrW47hy64clFQUROzj5Poy1Ur8ICVXEUpBsSqRuYEU2g==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@aws-sdk/middleware-user-agent": "3.967.0",
+        "@aws-sdk/types": "3.965.0",
+        "@smithy/node-config-provider": "^4.3.7",
+        "@smithy/types": "^4.11.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "peerDependencies": {
+        "aws-crt": ">=1.0.0"
+      },
+      "peerDependenciesMeta": {
+        "aws-crt": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@aws-sdk/xml-builder": {
+      "version": "3.965.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.965.0.tgz",
+      "integrity": "sha512-Tcod25/BTupraQwtb+Q+GX8bmEZfxIFjjJ/AvkhUZsZlkPeVluzq1uu3Oeqf145DCdMjzLIN6vab5MrykbDP+g==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/types": "^4.11.0",
+        "fast-xml-parser": "5.2.5",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@aws/lambda-invoke-store": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.4.tgz",
+      "integrity": "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
     "node_modules/@babel/code-frame": {
       "version": "7.29.0",
       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
@@ -960,6 +1662,587 @@
         "url": "https://opencollective.com/pkgr"
       }
     },
+    "node_modules/@smithy/abort-controller": {
+      "version": "4.2.12",
+      "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.12.tgz",
+      "integrity": "sha512-xolrFw6b+2iYGl6EcOL7IJY71vvyZ0DJ3mcKtpykqPe2uscwtzDZJa1uVQXyP7w9Dd+kGwYnPbMsJrGISKiY/Q==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/config-resolver": {
+      "version": "4.4.13",
+      "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.13.tgz",
+      "integrity": "sha512-iIzMC5NmOUP6WL6o8iPBjFhUhBZ9pPjpUpQYWMUFQqKyXXzOftbfK8zcQCz/jFV1Psmf05BK5ypx4K2r4Tnwdg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/node-config-provider": "^4.3.12",
+        "@smithy/types": "^4.13.1",
+        "@smithy/util-config-provider": "^4.2.2",
+        "@smithy/util-endpoints": "^3.3.3",
+        "@smithy/util-middleware": "^4.2.12",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/core": {
+      "version": "3.23.12",
+      "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.23.12.tgz",
+      "integrity": "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/protocol-http": "^5.3.12",
+        "@smithy/types": "^4.13.1",
+        "@smithy/url-parser": "^4.2.12",
+        "@smithy/util-base64": "^4.3.2",
+        "@smithy/util-body-length-browser": "^4.2.2",
+        "@smithy/util-middleware": "^4.2.12",
+        "@smithy/util-stream": "^4.5.20",
+        "@smithy/util-utf8": "^4.2.2",
+        "@smithy/uuid": "^1.1.2",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/credential-provider-imds": {
+      "version": "4.2.12",
+      "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.12.tgz",
+      "integrity": "sha512-cr2lR792vNZcYMriSIj+Um3x9KWrjcu98kn234xA6reOAFMmbRpQMOv8KPgEmLLtx3eldU6c5wALKFqNOhugmg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/node-config-provider": "^4.3.12",
+        "@smithy/property-provider": "^4.2.12",
+        "@smithy/types": "^4.13.1",
+        "@smithy/url-parser": "^4.2.12",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/fetch-http-handler": {
+      "version": "5.3.15",
+      "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.15.tgz",
+      "integrity": "sha512-T4jFU5N/yiIfrtrsb9uOQn7RdELdM/7HbyLNr6uO/mpkj1ctiVs7CihVr51w4LyQlXWDpXFn4BElf1WmQvZu/A==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/protocol-http": "^5.3.12",
+        "@smithy/querystring-builder": "^4.2.12",
+        "@smithy/types": "^4.13.1",
+        "@smithy/util-base64": "^4.3.2",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/hash-node": {
+      "version": "4.2.12",
+      "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.12.tgz",
+      "integrity": "sha512-QhBYbGrbxTkZ43QoTPrK72DoYviDeg6YKDrHTMJbbC+A0sml3kSjzFtXP7BtbyJnXojLfTQldGdUR0RGD8dA3w==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/types": "^4.13.1",
+        "@smithy/util-buffer-from": "^4.2.2",
+        "@smithy/util-utf8": "^4.2.2",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/invalid-dependency": {
+      "version": "4.2.12",
+      "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.12.tgz",
+      "integrity": "sha512-/4F1zb7Z8LOu1PalTdESFHR0RbPwHd3FcaG1sI3UEIriQTWakysgJr65lc1jj6QY5ye7aFsisajotH6UhWfm/g==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/is-array-buffer": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.2.2.tgz",
+      "integrity": "sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/middleware-content-length": {
+      "version": "4.2.12",
+      "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.12.tgz",
+      "integrity": "sha512-YE58Yz+cvFInWI/wOTrB+DbvUVz/pLn5mC5MvOV4fdRUc6qGwygyngcucRQjAhiCEbmfLOXX0gntSIcgMvAjmA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/protocol-http": "^5.3.12",
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/middleware-endpoint": {
+      "version": "4.4.27",
+      "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.27.tgz",
+      "integrity": "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/core": "^3.23.12",
+        "@smithy/middleware-serde": "^4.2.15",
+        "@smithy/node-config-provider": "^4.3.12",
+        "@smithy/shared-ini-file-loader": "^4.4.7",
+        "@smithy/types": "^4.13.1",
+        "@smithy/url-parser": "^4.2.12",
+        "@smithy/util-middleware": "^4.2.12",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/middleware-retry": {
+      "version": "4.4.44",
+      "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.44.tgz",
+      "integrity": "sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/node-config-provider": "^4.3.12",
+        "@smithy/protocol-http": "^5.3.12",
+        "@smithy/service-error-classification": "^4.2.12",
+        "@smithy/smithy-client": "^4.12.7",
+        "@smithy/types": "^4.13.1",
+        "@smithy/util-middleware": "^4.2.12",
+        "@smithy/util-retry": "^4.2.12",
+        "@smithy/uuid": "^1.1.2",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/middleware-serde": {
+      "version": "4.2.15",
+      "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.15.tgz",
+      "integrity": "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/core": "^3.23.12",
+        "@smithy/protocol-http": "^5.3.12",
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/middleware-stack": {
+      "version": "4.2.12",
+      "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.12.tgz",
+      "integrity": "sha512-kruC5gRHwsCOuyCd4ouQxYjgRAym2uDlCvQ5acuMtRrcdfg7mFBg6blaxcJ09STpt3ziEkis6bhg1uwrWU7txw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/node-config-provider": {
+      "version": "4.3.12",
+      "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.12.tgz",
+      "integrity": "sha512-tr2oKX2xMcO+rBOjobSwVAkV05SIfUKz8iI53rzxEmgW3GOOPOv0UioSDk+J8OpRQnpnhsO3Af6IEBabQBVmiw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/property-provider": "^4.2.12",
+        "@smithy/shared-ini-file-loader": "^4.4.7",
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/node-http-handler": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.5.0.tgz",
+      "integrity": "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/abort-controller": "^4.2.12",
+        "@smithy/protocol-http": "^5.3.12",
+        "@smithy/querystring-builder": "^4.2.12",
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/property-provider": {
+      "version": "4.2.12",
+      "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.12.tgz",
+      "integrity": "sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/protocol-http": {
+      "version": "5.3.12",
+      "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.12.tgz",
+      "integrity": "sha512-fit0GZK9I1xoRlR4jXmbLhoN0OdEpa96ul8M65XdmXnxXkuMxM0Y8HDT0Fh0Xb4I85MBvBClOzgSrV1X2s1Hxw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/querystring-builder": {
+      "version": "4.2.12",
+      "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.12.tgz",
+      "integrity": "sha512-6wTZjGABQufekycfDGMEB84BgtdOE/rCVTov+EDXQ8NHKTUNIp/j27IliwP7tjIU9LR+sSzyGBOXjeEtVgzCHg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/types": "^4.13.1",
+        "@smithy/util-uri-escape": "^4.2.2",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/querystring-parser": {
+      "version": "4.2.12",
+      "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.12.tgz",
+      "integrity": "sha512-P2OdvrgiAKpkPNKlKUtWbNZKB1XjPxM086NeVhK+W+wI46pIKdWBe5QyXvhUm3MEcyS/rkLvY8rZzyUdmyDZBw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/service-error-classification": {
+      "version": "4.2.12",
+      "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.12.tgz",
+      "integrity": "sha512-LlP29oSQN0Tw0b6D0Xo6BIikBswuIiGYbRACy5ujw/JgWSzTdYj46U83ssf6Ux0GyNJVivs2uReU8pt7Eu9okQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/types": "^4.13.1"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/shared-ini-file-loader": {
+      "version": "4.4.7",
+      "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.7.tgz",
+      "integrity": "sha512-HrOKWsUb+otTeo1HxVWeEb99t5ER1XrBi/xka2Wv6NVmTbuCUC1dvlrksdvxFtODLBjsC+PHK+fuy2x/7Ynyiw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/signature-v4": {
+      "version": "5.3.12",
+      "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.12.tgz",
+      "integrity": "sha512-B/FBwO3MVOL00DaRSXfXfa/TRXRheagt/q5A2NM13u7q+sHS59EOVGQNfG7DkmVtdQm5m3vOosoKAXSqn/OEgw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/is-array-buffer": "^4.2.2",
+        "@smithy/protocol-http": "^5.3.12",
+        "@smithy/types": "^4.13.1",
+        "@smithy/util-hex-encoding": "^4.2.2",
+        "@smithy/util-middleware": "^4.2.12",
+        "@smithy/util-uri-escape": "^4.2.2",
+        "@smithy/util-utf8": "^4.2.2",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/smithy-client": {
+      "version": "4.12.7",
+      "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.12.7.tgz",
+      "integrity": "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/core": "^3.23.12",
+        "@smithy/middleware-endpoint": "^4.4.27",
+        "@smithy/middleware-stack": "^4.2.12",
+        "@smithy/protocol-http": "^5.3.12",
+        "@smithy/types": "^4.13.1",
+        "@smithy/util-stream": "^4.5.20",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/types": {
+      "version": "4.13.1",
+      "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.13.1.tgz",
+      "integrity": "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/url-parser": {
+      "version": "4.2.12",
+      "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.12.tgz",
+      "integrity": "sha512-wOPKPEpso+doCZGIlr+e1lVI6+9VAKfL4kZWFgzVgGWY2hZxshNKod4l2LXS3PRC9otH/JRSjtEHqQ/7eLciRA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/querystring-parser": "^4.2.12",
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/util-base64": {
+      "version": "4.3.2",
+      "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.3.2.tgz",
+      "integrity": "sha512-XRH6b0H/5A3SgblmMa5ErXQ2XKhfbQB+Fm/oyLZ2O2kCUrwgg55bU0RekmzAhuwOjA9qdN5VU2BprOvGGUkOOQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/util-buffer-from": "^4.2.2",
+        "@smithy/util-utf8": "^4.2.2",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/util-body-length-browser": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.2.tgz",
+      "integrity": "sha512-JKCrLNOup3OOgmzeaKQwi4ZCTWlYR5H4Gm1r2uTMVBXoemo1UEghk5vtMi1xSu2ymgKVGW631e2fp9/R610ZjQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/util-body-length-node": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.2.3.tgz",
+      "integrity": "sha512-ZkJGvqBzMHVHE7r/hcuCxlTY8pQr1kMtdsVPs7ex4mMU+EAbcXppfo5NmyxMYi2XU49eqaz56j2gsk4dHHPG/g==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/util-buffer-from": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.2.2.tgz",
+      "integrity": "sha512-FDXD7cvUoFWwN6vtQfEta540Y/YBe5JneK3SoZg9bThSoOAC/eGeYEua6RkBgKjGa/sz6Y+DuBZj3+YEY21y4Q==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/is-array-buffer": "^4.2.2",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/util-config-provider": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.2.tgz",
+      "integrity": "sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/util-defaults-mode-browser": {
+      "version": "4.3.43",
+      "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.43.tgz",
+      "integrity": "sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/property-provider": "^4.2.12",
+        "@smithy/smithy-client": "^4.12.7",
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/util-defaults-mode-node": {
+      "version": "4.2.47",
+      "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.47.tgz",
+      "integrity": "sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/config-resolver": "^4.4.13",
+        "@smithy/credential-provider-imds": "^4.2.12",
+        "@smithy/node-config-provider": "^4.3.12",
+        "@smithy/property-provider": "^4.2.12",
+        "@smithy/smithy-client": "^4.12.7",
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/util-endpoints": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.3.3.tgz",
+      "integrity": "sha512-VACQVe50j0HZPjpwWcjyT51KUQ4AnsvEaQ2lKHOSL4mNLD0G9BjEniQ+yCt1qqfKfiAHRAts26ud7hBjamrwig==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/node-config-provider": "^4.3.12",
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/util-hex-encoding": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.2.tgz",
+      "integrity": "sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/util-middleware": {
+      "version": "4.2.12",
+      "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.12.tgz",
+      "integrity": "sha512-Er805uFUOvgc0l8nv0e0su0VFISoxhJ/AwOn3gL2NWNY2LUEldP5WtVcRYSQBcjg0y9NfG8JYrCJaYDpupBHJQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/util-retry": {
+      "version": "4.2.12",
+      "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.12.tgz",
+      "integrity": "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/service-error-classification": "^4.2.12",
+        "@smithy/types": "^4.13.1",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/util-stream": {
+      "version": "4.5.20",
+      "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.20.tgz",
+      "integrity": "sha512-4yXLm5n/B5SRBR2p8cZ90Sbv4zL4NKsgxdzCzp/83cXw2KxLEumt5p+GAVyRNZgQOSrzXn9ARpO0lUe8XSlSDw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/fetch-http-handler": "^5.3.15",
+        "@smithy/node-http-handler": "^4.5.0",
+        "@smithy/types": "^4.13.1",
+        "@smithy/util-base64": "^4.3.2",
+        "@smithy/util-buffer-from": "^4.2.2",
+        "@smithy/util-hex-encoding": "^4.2.2",
+        "@smithy/util-utf8": "^4.2.2",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/util-uri-escape": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.2.tgz",
+      "integrity": "sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/util-utf8": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.2.tgz",
+      "integrity": "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@smithy/util-buffer-from": "^4.2.2",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@smithy/uuid": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.2.tgz",
+      "integrity": "sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
     "node_modules/@teppeis/multimaps": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/@teppeis/multimaps/-/multimaps-3.0.0.tgz",
@@ -1216,6 +2499,12 @@
       "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
       "dev": true
     },
+    "node_modules/bowser": {
+      "version": "2.14.1",
+      "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz",
+      "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==",
+      "license": "MIT"
+    },
     "node_modules/brace-expansion": {
       "version": "1.1.12",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
@@ -1957,6 +3246,24 @@
       "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
       "dev": true
     },
+    "node_modules/fast-xml-parser": {
+      "version": "5.2.5",
+      "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz",
+      "integrity": "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/NaturalIntelligence"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "strnum": "^2.1.0"
+      },
+      "bin": {
+        "fxparser": "src/cli/cli.js"
+      }
+    },
     "node_modules/figures": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
@@ -3677,6 +4984,18 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/strnum": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.1.tgz",
+      "integrity": "sha512-BwRvNd5/QoAtyW1na1y1LsJGQNvRlkde6Q/ipqqEaivoMdV+B1OMOTVdwR+N/cwVUcIt9PYyHmV8HyexCZSupg==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/NaturalIntelligence"
+        }
+      ],
+      "license": "MIT"
+    },
     "node_modules/supports-color": {
       "version": "8.1.1",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
@@ -3807,8 +5126,7 @@
     "node_modules/tslib": {
       "version": "2.8.1",
       "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
-      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
-      "dev": true
+      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
     },
     "node_modules/type-check": {
       "version": "0.4.0",
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json b/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json
index e048f5c12b..299f7d1f7c 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json
@@ -27,6 +27,9 @@
     "build"
   ],
   "dependencies": {
+    "@aws-sdk/credential-providers": "^3.967.0",
+    "@smithy/hash-node": "^4.2.12",
+    "@smithy/signature-v4": "^5.3.12",
     "buffer": "^6.0.3",
     "eventemitter3": "^5.0.1",
     "readable-stream": "^4.5.2",
@@ -34,6 +37,7 @@
   },
   "devDependencies": {
     "@cucumber/cucumber": "~12.7.0",
+    "@eslint/js": "^9.16.0",
     "@knighted/duel": "^1.0.7",
     "@tsconfig/node18": "^18.2.2",
     "@types/readable-stream": "^4.0.10",
@@ -42,13 +46,12 @@
     "chai-string": "~1.5.0",
     "colors": "1.4.0",
     "cross-env": "^10.1.0",
-    "@eslint/js": "^9.16.0",
     "eslint": "^9.36.0",
     "eslint-config-prettier": "^10.0.1",
     "eslint-plugin-prettier": "^5.0.0",
     "globals": "^15.14.0",
-    "jsdoc": "^4.0.5",
     "js-yaml": "^3.14.2",
+    "jsdoc": "^4.0.5",
     "mocha": "^11.7.5",
     "prettier": "^3.0.0",
     "ts-node": "^10.9.2",
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js
index b8eec336a1..a030de4eff 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js
@@ -56,6 +56,24 @@ export function getClient(traversalSource) {
   return new Client(serverUrl, { traversalSource, mimeType: process.env.CLIENT_MIMETYPE });
 }
 
+export function getAuthenticatedClient(traversalSource, interceptors) {
+  return new Client(serverAuthUrl, {
+    traversalSource,
+    mimeType: process.env.CLIENT_MIMETYPE,
+    rejectUnauthorized: false,
+    interceptors,
+  });
+}
+
+export function getAuthenticatedConnection(traversalSource, interceptors) {
+  return new DriverRemoteConnection(serverAuthUrl, {
+    traversalSource,
+    mimeType: process.env.CLIENT_MIMETYPE,
+    rejectUnauthorized: false,
+    interceptors,
+  });
+}
+
 function getMimeTypeFromSocketServerSettings(socketServerSettings) {
   return 'application/vnd.graphbinary-v4.0';
 }
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/auth-tests.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/auth-tests.js
new file mode 100644
index 0000000000..56302ae02d
--- /dev/null
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/auth-tests.js
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+import assert from 'assert';
+import anon from '../../lib/process/anonymous-traversal.js';
+import { basic } from '../../lib/driver/auth.js';
+import { getAuthenticatedClient, getAuthenticatedConnection } from '../helper.js';
+
+/**
+ * Integration tests for basic authentication.
+ *
+ * These tests require a Gremlin Server running with authentication enabled
+ * on the auth URL (default: https://localhost:45941/gremlin).
+ *
+ * To run:
+ *   NODE_TLS_REJECT_UNAUTHORIZED=0 RUN_BASIC_AUTH_INTEGRATION_TESTS=true npm run integration-test
+ */
+describe('Basic Auth Integration', function () {
+  const runAuthTests = process.env.RUN_BASIC_AUTH_INTEGRATION_TESTS === 'true';
+
+  before(function () {
+    if (!runAuthTests) {
+      this.skip();
+    }
+  });
+
+  describe('Client with basic auth', function () {
+    let client;
+
+    before(function () {
+      client = getAuthenticatedClient('gmodern', basic('stephen', 'password'));
+      return client.open();
+    });
+
+    after(function () {
+      return client.close();
+    });
+
+    it('should authenticate and submit a traversal', async function () {
+      const result = await client.submit('g.V().count()');
+      assert.ok(result);
+      assert.strictEqual(result.first(), 6);
+    });
+  });
+
+  describe('DriverRemoteConnection with basic auth', function () {
+    let connection;
+
+    before(function () {
+      connection = getAuthenticatedConnection('gmodern', basic('stephen', 'password'));
+      return connection.open();
+    });
+
+    after(function () {
+      return connection.close();
+    });
+
+    it('should authenticate and execute traversal', async function () {
+      const g = anon.traversal().with_(connection);
+      const count = await g.V().count().toList();
+      assert.ok(count);
+      assert.strictEqual(count[0], 6);
+    });
+  });
+});
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/auth-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/auth-test.js
new file mode 100644
index 0000000000..2d112ce4de
--- /dev/null
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/auth-test.js
@@ -0,0 +1,124 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+import assert from 'assert';
+import { Buffer } from 'buffer';
+import { basic, sigv4 } from '../../lib/driver/auth.js';
+
+describe('auth', function () {
+  describe('basic', function () {
+    function createMockRequest() {
+      return {
+        url: 'https://localhost:8182/gremlin',
+        method: 'POST',
+        headers: {
+          'content-type': 'application/vnd.graphbinary-v4.0',
+          'accept': 'application/vnd.graphbinary-v4.0',
+        },
+        body: new Uint8Array(0),
+      };
+    }
+
+    it('should add authorization header', function () {
+      const request = createMockRequest();
+      assert.strictEqual(request.headers['authorization'], undefined);
+
+      const interceptor = basic('username', 'password');
+      const result = interceptor(request);
+
+      assert.ok(result.headers['authorization'].startsWith('Basic '));
+    });
+
+    it('should encode credentials correctly', function () {
+      const request = createMockRequest();
+      const interceptor = basic('username', 'password');
+      const result = interceptor(request);
+
+      const encoded = result.headers['authorization'].substring('Basic '.length);
+      const decoded = Buffer.from(encoded, 'base64').toString();
+      assert.strictEqual(decoded, 'username:password');
+    });
+
+    it('should return the same request object', function () {
+      const request = createMockRequest();
+      const interceptor = basic('username', 'password');
+      const result = interceptor(request);
+
+      assert.strictEqual(result, request);
+    });
+  });
+
+  describe('sigv4', function () {
+    function createMockRequest() {
+      return {
+        url: 'https://localhost:8182/gremlin',
+        method: 'POST',
+        headers: {
+          'content-type': 'application/vnd.graphbinary-v4.0',
+          'accept': 'application/vnd.graphbinary-v4.0',
+        },
+        body: new Uint8Array(Buffer.from('{"gremlin":"g.V()"}')),
+      };
+    }
+
+    const mockProvider = () => ({
+      accessKeyId: 'MOCK_ACCESS_KEY',
+      secretAccessKey: 'MOCK_SECRET_KEY',
+    });
+
+    it('should add signed headers', async function () {
+      const request = createMockRequest();
+      assert.strictEqual(request.headers['authorization'], undefined);
+
+      const interceptor = sigv4('xx-dummy-1', 'test-service', mockProvider);
+      const result = await interceptor(request);
+
+      assert.ok(result.headers['x-amz-date']);
+      const authHeader = result.headers['authorization'];
+      assert.ok(authHeader.startsWith('AWS4-HMAC-SHA256 Credential=MOCK_ACCESS_KEY'));
+      assert.ok(authHeader.includes('xx-dummy-1/test-service/aws4_request'));
+      assert.ok(authHeader.includes('Signature='));
+    });
+
+    it('should add session token when provided', async function () {
+      const request = createMockRequest();
+      const providerWithToken = () => ({
+        accessKeyId: 'MOCK_ACCESS_KEY',
+        secretAccessKey: 'MOCK_SECRET_KEY',
+        sessionToken: 'MOCK_SESSION_TOKEN',
+      });
+
+      const interceptor = sigv4('xx-dummy-1', 'test-service', providerWithToken);
+      const result = await interceptor(request);
+
+      assert.strictEqual(result.headers['x-amz-security-token'], 'MOCK_SESSION_TOKEN');
+      const authHeader = result.headers['authorization'];
+      assert.ok(authHeader.startsWith('AWS4-HMAC-SHA256 Credential='));
+      assert.ok(authHeader.includes('Signature='));
+    });
+
+    it('should return the same request object', async function () {
+      const request = createMockRequest();
+      const interceptor = sigv4('xx-dummy-1', 'test-service', mockProvider);
+      const result = await interceptor(request);
+
+      assert.strictEqual(result, request);
+    });
+  });
+});
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/exports-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/exports-test.js
index 55e0b58c8f..3f5adb88bf 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/exports-test.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/exports-test.js
@@ -70,6 +70,8 @@ describe('API', function () {
     validateConstructor(glvModule.driver, 'DriverRemoteConnection');
     validateConstructor(glvModule.driver, 'Client');
     validateConstructor(glvModule.driver, 'ResultSet');
+    assert.strictEqual(typeof glvModule.driver.auth.basic, 'function');
+    assert.strictEqual(typeof glvModule.driver.auth.sigv4, 'function');
   });
 });
 


(tinkerpop) 02/02: Remove mimeType configuration in favour of reader and writer options, make writer optional.

Posted by co...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

colegreer pushed a commit to branch js-interceptors
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 1093638a8dcf39120e36fc1a1ec6909e874adcde
Author: Cole Greer <Co...@improving.com>
AuthorDate: Sat Mar 21 20:08:11 2026 -0700

    Remove mimeType configuration in favour of reader and writer options, make writer optional.
---
 CHANGELOG.asciidoc                                 |  1 +
 gremlin-javascript/examples/node/connections.js    |  1 -
 .../gremlin-javascript/lib/driver/client.ts        |  1 -
 .../gremlin-javascript/lib/driver/connection.ts    | 48 +++++++++-------------
 .../lib/driver/driver-remote-connection.ts         |  1 -
 .../io/binary/internals/GraphBinaryReader.js       |  4 ++
 .../io/binary/internals/GraphBinaryWriter.js       |  8 +++-
 .../javascript/gremlin-javascript/test/helper.js   | 40 ++----------------
 .../gremlin-javascript/test/unit/auth-test.js      |  2 -
 .../gremlin-javascript/test/unit/client-test.js    | 10 -----
 10 files changed, 33 insertions(+), 83 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 76b6cfd1a0..20b91b08eb 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -37,6 +37,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 * Added `RequestInterceptor` to `gremlin-go` with `auth` reference implementations to replace `authInfo`.
 * Refactored GraphBinary serializers to use `io.Writer` and `io.Reader` instead of `*bytes.Buffer` for streaming capacities.
 * Refactored `httpProtocol` and `httpTransport` in `gremlin-go` into single `connection.go` that handles HTTP request and response.
+* Removed `mimeType` connection option in `gremlin-javascript` in favor of direct use of `reader` and `writer` options.
 * Bumped ANTLR to 4.13.2
 * Bumped SLF4j to 2.0.16.
 * Bumped GMavenPlus to 4.1.1.
diff --git a/gremlin-javascript/examples/node/connections.js b/gremlin-javascript/examples/node/connections.js
index a61431478f..e8d8841214 100644
--- a/gremlin-javascript/examples/node/connections.js
+++ b/gremlin-javascript/examples/node/connections.js
@@ -46,7 +46,6 @@ async function withRemote() {
 async function withConfigs() {
     // Connecting and customizing configurations
     const dc = new DriverRemoteConnection(serverUrl, {
-        mimeType: 'application/vnd.graphbinary-v4.0',
         rejectUnauthorized: false,
         traversalSource: 'g',
     });
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.ts
index a74c0081c9..e44dc345b8 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.ts
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.ts
@@ -47,7 +47,6 @@ export default class Client {
    * @param {Object} [options] The connection options.
    * @param {Array} [options.ca] Trusted certificates.
    * @param {String|Array|Buffer} [options.cert] The certificate key.
-   * @param {String} [options.mimeType] The mime type to use.
    * @param {String|Buffer} [options.pfx] The private key, certificate, and CA certs.
    * @param {GraphBinaryReader} [options.reader] The reader to use.
    * @param {Boolean} [options.rejectUnauthorized] Determines whether to verify or not the server certificate.
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.ts
index 1e2b1d1560..1afb320a3f 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.ts
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.ts
@@ -42,16 +42,11 @@ const responseStatusCode = {
   authenticationChallenge: 407,
 };
 
-const defaultMimeType = 'application/vnd.graphbinary-v4.0';
-const graphBinaryMimeType = 'application/vnd.graphbinary-v4.0';
-
-type MimeType = typeof defaultMimeType | typeof graphBinaryMimeType;
-
 export type HttpRequest = {
   url: string;
   method: string;
   headers: Record<string, string>;
-  body: Uint8Array;
+  body: any;
 };
 
 export type RequestInterceptor = (request: HttpRequest) => HttpRequest | Promise<HttpRequest>;
@@ -59,12 +54,11 @@ export type RequestInterceptor = (request: HttpRequest) => HttpRequest | Promise
 export type ConnectionOptions = {
   ca?: string[];
   cert?: string | string[] | Buffer;
-  mimeType?: MimeType; //TODO:: Revisit if MimeType should remain configurable
   pfx?: string | Buffer;
   reader?: any;
   rejectUnauthorized?: boolean;
   traversalSource?: string;
-  writer?: any;
+  writer?: any | null;
   headers?: Record<string, string | string[]>;
   enableUserAgentOnConnect?: boolean;
   agent?: Agent;
@@ -75,10 +69,8 @@ export type ConnectionOptions = {
  * Represents a single connection to a Gremlin Server.
  */
 export default class Connection extends EventEmitter {
-  readonly mimeType: MimeType;
-
   private readonly _reader: any;
-  private readonly _writer: any;
+  private readonly _writer: any | null;
 
   isOpen = true;
   traversalSource: string;
@@ -92,12 +84,11 @@ export default class Connection extends EventEmitter {
    * @param {Object} [options] The connection options.
    * @param {Array} [options.ca] Trusted certificates.
    * @param {String|Array|Buffer} [options.cert] The certificate key.
-   * @param {String} [options.mimeType] The mime type to use.
    * @param {String|Buffer} [options.pfx] The private key, certificate, and CA certs.
    * @param {GraphBinaryReader} [options.reader] The reader to use.
    * @param {Boolean} [options.rejectUnauthorized] Determines whether to verify or not the server certificate.
    * @param {String} [options.traversalSource] The traversal source. Defaults to: 'g'.
-   * @param {GraphBinaryWriter} [options.writer] The writer to use.
+   * @param {GraphBinaryWriter} [options.writer] The writer to use. Set to null to skip serialization.
    * @param {Object} [options.headers] An associative array containing the additional header key/values for the initial request.
    * @param {Boolean} [options.enableUserAgentOnConnect] Determines if a user agent will be sent during connection handshake. Defaults to: true
    * @param {http.Agent} [options.agent] The http.Agent implementation to use.
@@ -110,13 +101,8 @@ export default class Connection extends EventEmitter {
   ) {
     super();
 
-    /**
-     * Gets the MIME type.
-     * @type {String}
-     */
-    this.mimeType = options.mimeType || defaultMimeType;
     this._reader = options.reader || graphBinaryReader;
-    this._writer = options.writer || graphBinaryWriter;
+    this._writer = 'writer' in options ? options.writer : graphBinaryWriter;
     this.traversalSource = options.traversalSource || 'g';
     this._enableUserAgentOnConnect = options.enableUserAgentOnConnect !== false;
 
@@ -143,9 +129,10 @@ export default class Connection extends EventEmitter {
 
   /** @override */
   submit(request: RequestMessage) {
-    const request_buf: Buffer = this._writer.writeRequest(request);
+    // The user may not want the body to be serialized if they are using an interceptor.
+    const body = this._writer ? this._writer.writeRequest(request) : request;
     
-    return this.#makeHttpRequest(request_buf)
+    return this.#makeHttpRequest(body)
         .then((response) => {
           return this.#handleResponse(response);
         });
@@ -161,19 +148,22 @@ export default class Connection extends EventEmitter {
       return this._reader;
     }
 
-    if (contentType === graphBinaryMimeType) {
-      return graphBinaryReader;
+    if (contentType === this._reader.mimeType) {
+      return this._reader;
     }
 
     return null;
   }
 
-  async #makeHttpRequest(request_buf: Buffer): Promise<Response> {
+  async #makeHttpRequest(body: any): Promise<Response> {
     const headers: Record<string, string> = {
-      'Content-Type': this.mimeType,
-      'Accept': this.mimeType
+      'Accept': this._reader.mimeType
     };
 
+    if (this._writer) {
+      headers['Content-Type'] = this._writer.mimeType;
+    }
+
     if (this._enableUserAgentOnConnect) {
       const userAgent = await utils.getUserAgent();
       if (userAgent !== undefined) {
@@ -190,7 +180,7 @@ export default class Connection extends EventEmitter {
       url: this.url,
       method: 'POST',
       headers,
-      body: new Uint8Array(request_buf),
+      body,
     };
 
     for (const interceptor of this._interceptors) {
@@ -200,7 +190,7 @@ export default class Connection extends EventEmitter {
     return fetch(httpRequest.url, {
       method: httpRequest.method,
       headers: httpRequest.headers,
-      body: httpRequest.body as BodyInit,
+      body: httpRequest.body,
     });
   }
 
@@ -247,7 +237,7 @@ export default class Connection extends EventEmitter {
     }
 
     if (!reader) {
-      throw new Error(`Unsupported Content-Type: ${contentType}`);
+      throw new Error(`Response Content-Type '${contentType}' does not match the configured reader (expected '${this._reader.mimeType}')`);
     }
 
     const deserialized = reader.readResponse(buffer);
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.ts
index ad9dd8b4cf..c59c010834 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.ts
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.ts
@@ -41,7 +41,6 @@ export default class DriverRemoteConnection extends RemoteConnection {
    * @param {ConnectionOptions} [options] The connection options.
    * @param {Array} [options.ca] Trusted certificates.
    * @param {String|Array|Buffer} [options.cert] The certificate key.
-   * @param {String} [options.mimeType] The mime type to use.
    * @param {String|Buffer} [options.pfx] The private key, certificate, and CA certs.
    * @param {GraphBinaryReader} [options.reader] The reader to use.
    * @param {Boolean} [options.rejectUnauthorized] Determines whether to verify or not the server certificate.
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryReader.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryReader.js
index 83c6352ca3..d75bf13635 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryReader.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryReader.js
@@ -31,6 +31,10 @@ export default class GraphBinaryReader {
     this.ioc = ioc;
   }
 
+  get mimeType() {
+    return 'application/vnd.graphbinary-v4.0';
+  }
+
   readResponse(buffer) {
     if (buffer === undefined || buffer === null) {
       throw new Error('Buffer is missing.');
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryWriter.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryWriter.js
index 87ba1f5e21..f0ca979a72 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryWriter.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryWriter.js
@@ -31,6 +31,10 @@ export default class GraphBinaryWriter {
     this.ioc = ioc;
   }
 
+  get mimeType() {
+    return 'application/vnd.graphbinary-v4.0';
+  }
+
   writeRequest(requestMessage) {
     const fields = new Map();
 
@@ -73,7 +77,7 @@ export default class GraphBinaryWriter {
         this.ioc.mapSerializer.serialize(fields, false),
         this.ioc.stringSerializer.serialize(gremlin, false),
       ];
-      return Buffer.concat(bufs);
+      return new Uint8Array(Buffer.concat(bufs));
     }
 
     // Legacy path: plain object with { gremlin, fields }
@@ -82,6 +86,6 @@ export default class GraphBinaryWriter {
       this.ioc.mapSerializer.serialize(requestMessage.fields || new Map(), false),
       this.ioc.stringSerializer.serialize(requestMessage.gremlin, false),
     ];
-    return Buffer.concat(bufs);
+    return new Uint8Array(Buffer.concat(bufs));
   }
 }
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js
index a030de4eff..42926b323d 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js
@@ -24,42 +24,32 @@
 import DriverRemoteConnection from '../lib/driver/driver-remote-connection.js';
 import Client from '../lib/driver/client.js';
 
-import jsYaml from 'js-yaml';
-import fs from 'fs';
-
 let serverUrl;
 let serverAuthUrl;
-let socketServerUrl;
-let sockerServerConfigPath;
 if (process.env.DOCKER_ENVIRONMENT === 'true') {
   serverUrl = 'http://gremlin-server-test-js:45940/gremlin';
   serverAuthUrl = 'https://gremlin-server-test-js:45941/gremlin';
-  socketServerUrl = 'http://gremlin-socket-server-js:';
-  sockerServerConfigPath = '/js_app/gremlin-socket-server/conf/test-ws-gremlin.yaml';
 } else {
   serverUrl = 'http://localhost:45940/gremlin';
   serverAuthUrl = 'https://localhost:45941/gremlin';
-  socketServerUrl = 'http://localhost:';
-  sockerServerConfigPath = '../../../../../gremlin-tools/gremlin-socket-server/conf/test-ws-gremlin.yaml';
 }
 
 /** @returns {DriverRemoteConnection} */
 export function getConnection(traversalSource) {
-  return new DriverRemoteConnection(serverUrl, { traversalSource, mimeType: process.env.CLIENT_MIMETYPE });
+  return new DriverRemoteConnection(serverUrl, { traversalSource });
 }
 
 export function getDriverRemoteConnection(url, options) {
-  return new DriverRemoteConnection(url, { ...options, mimeType: process.env.CLIENT_MIMETYPE });
+  return new DriverRemoteConnection(url, { ...options });
 }
 
 export function getClient(traversalSource) {
-  return new Client(serverUrl, { traversalSource, mimeType: process.env.CLIENT_MIMETYPE });
+  return new Client(serverUrl, { traversalSource });
 }
 
 export function getAuthenticatedClient(traversalSource, interceptors) {
   return new Client(serverAuthUrl, {
     traversalSource,
-    mimeType: process.env.CLIENT_MIMETYPE,
     rejectUnauthorized: false,
     interceptors,
   });
@@ -68,31 +58,7 @@ export function getAuthenticatedClient(traversalSource, interceptors) {
 export function getAuthenticatedConnection(traversalSource, interceptors) {
   return new DriverRemoteConnection(serverAuthUrl, {
     traversalSource,
-    mimeType: process.env.CLIENT_MIMETYPE,
     rejectUnauthorized: false,
     interceptors,
   });
 }
-
-function getMimeTypeFromSocketServerSettings(socketServerSettings) {
-  return 'application/vnd.graphbinary-v4.0';
-}
-
-export function getGremlinSocketServerClient(traversalSource) {
-  const settings = getGremlinSocketServerSettings();
-  const url = socketServerUrl + settings.PORT + '/gremlin';
-  let mimeType = getMimeTypeFromSocketServerSettings(settings)
-  return new Client(url, { traversalSource, mimeType });
-}
-
-export const getGremlinSocketServerClientNoUserAgent = function getGremlinSocketServerClient(traversalSource) {
-  const settings = getGremlinSocketServerSettings();
-  const url = socketServerUrl + settings.PORT + '/gremlin';
-  let mimeType = getMimeTypeFromSocketServerSettings(settings)
-  return new Client(url, { traversalSource, mimeType, enableUserAgentOnConnect:false });
-};
-
-export function getGremlinSocketServerSettings() {
-  const settings = jsYaml.load(fs.readFileSync(sockerServerConfigPath, 'utf8'));
-  return settings;
-}
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/auth-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/auth-test.js
index 2d112ce4de..cab2a5d24f 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/auth-test.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/auth-test.js
@@ -28,7 +28,6 @@ describe('auth', function () {
         url: 'https://localhost:8182/gremlin',
         method: 'POST',
         headers: {
-          'content-type': 'application/vnd.graphbinary-v4.0',
           'accept': 'application/vnd.graphbinary-v4.0',
         },
         body: new Uint8Array(0),
@@ -70,7 +69,6 @@ describe('auth', function () {
         url: 'https://localhost:8182/gremlin',
         method: 'POST',
         headers: {
-          'content-type': 'application/vnd.graphbinary-v4.0',
           'accept': 'application/vnd.graphbinary-v4.0',
         },
         body: new Uint8Array(Buffer.from('{"gremlin":"g.V()"}')),
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/client-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/client-test.js
index 4f28f0f5ef..38342a3a9f 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/client-test.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/client-test.js
@@ -51,14 +51,4 @@ describe('Client', function () {
     customClient._connection = connectionMock;
     customClient.submit(query)
   });
-
-  it('should use default mimeType', function () {
-    const customClient = new Client('http://localhost:9321', {traversalSource: 'g', connectOnStartup: false});
-    assert.strictEqual(customClient._connection.mimeType, 'application/vnd.graphbinary-v4.0')
-  });
-
-  it('should use given mimeType', function () {
-    const customClient = new Client('http://localhost:9321', {traversalSource: 'g', connectOnStartup: false, mimeType: 'application/vnd.gremlin-v2.0+json'});
-    assert.strictEqual(customClient._connection.mimeType, 'application/vnd.gremlin-v2.0+json')
-  });
 });