diff --git a/core/generator/gapic-generator-typescript/baselines/pubsub-api-dump-esm/api.json.baseline b/core/generator/gapic-generator-typescript/baselines/pubsub-api-dump-esm/api.json.baseline
index 6de2dfd0024e..c72641534d0a 100644
--- a/core/generator/gapic-generator-typescript/baselines/pubsub-api-dump-esm/api.json.baseline
+++ b/core/generator/gapic-generator-typescript/baselines/pubsub-api-dump-esm/api.json.baseline
@@ -5105,6 +5105,7 @@
]
}
],
+ "resumableUploads": [],
"longRunning": [],
"diregapicLRO": [],
"streaming": [],
@@ -10252,6 +10253,7 @@
]
}
],
+ "resumableUploads": [],
"longRunning": [],
"diregapicLRO": [],
"streaming": [],
@@ -16698,6 +16700,7 @@
]
}
],
+ "resumableUploads": [],
"longRunning": [],
"diregapicLRO": [],
"streaming": [
diff --git a/core/generator/gapic-generator-typescript/baselines/pubsub-api-dump/api.json.baseline b/core/generator/gapic-generator-typescript/baselines/pubsub-api-dump/api.json.baseline
index 6de2dfd0024e..c72641534d0a 100644
--- a/core/generator/gapic-generator-typescript/baselines/pubsub-api-dump/api.json.baseline
+++ b/core/generator/gapic-generator-typescript/baselines/pubsub-api-dump/api.json.baseline
@@ -5105,6 +5105,7 @@
]
}
],
+ "resumableUploads": [],
"longRunning": [],
"diregapicLRO": [],
"streaming": [],
@@ -10252,6 +10253,7 @@
]
}
],
+ "resumableUploads": [],
"longRunning": [],
"diregapicLRO": [],
"streaming": [],
@@ -16698,6 +16700,7 @@
]
}
],
+ "resumableUploads": [],
"longRunning": [],
"diregapicLRO": [],
"streaming": [
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/.OwlBot.yaml.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/.OwlBot.yaml.baseline
new file mode 100644
index 000000000000..7feea79e8531
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/.OwlBot.yaml.baseline
@@ -0,0 +1,19 @@
+# Copyright 2025 Google LLC
+#
+# Licensed 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.
+
+deep-copy-regex:
+ - source: /google/samples/resumable/google-samples-resumable-nodejs
+ dest: /owl-bot-staging/google-samples-resumable
+
+api-name: resumable
\ No newline at end of file
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/.babelrc.json.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/.babelrc.json.baseline
new file mode 100644
index 000000000000..940d91b0a07b
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/.babelrc.json.baseline
@@ -0,0 +1,19 @@
+{
+ "presets": [
+ "@babel/preset-typescript",
+ "@babel/env"
+ ],
+ "plugins": [
+ [
+ "replace-import-extension",
+ {
+ "extMapping": {
+ ".js": ".cjs"
+ }
+ }
+ ],
+ "./node_modules/gapic-tools/build/src/replaceESMMockingLib.js",
+ "./node_modules/gapic-tools/build/src/replaceImportMetaUrl.js",
+ "./node_modules/gapic-tools/build/src/toggleESMFlagVariable.js"
+ ]
+}
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/.gitignore.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/.gitignore.baseline
new file mode 100644
index 000000000000..b391f5f9cd1a
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/.gitignore.baseline
@@ -0,0 +1,15 @@
+**/*.log
+**/node_modules
+/.coverage
+/coverage
+/.nyc_output
+/docs/
+/out/
+/build/
+system-test/secrets.js
+system-test/*key.json
+*.lock
+.DS_Store
+package-lock.json
+__pycache__
+esm/**/*.d.ts
\ No newline at end of file
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/.jsdoc.cjs.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/.jsdoc.cjs.baseline
new file mode 100644
index 000000000000..de732583739e
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/.jsdoc.cjs.baseline
@@ -0,0 +1,54 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+
+module.exports = {
+ opts: {
+ readme: './README.md',
+ package: './package.json',
+ template: './node_modules/jsdoc-fresh',
+ recurse: true,
+ verbose: true,
+ destination: './docs/'
+ },
+ plugins: [
+ 'plugins/markdown',
+ 'jsdoc-region-tag'
+ ],
+ source: {
+ excludePattern: '(^|\\/|\\\\)[._]',
+ include: [
+ 'build/src',
+ 'protos'
+ ],
+ includePattern: '\\.js$'
+ },
+ templates: {
+ copyright: 'Copyright 2026 Google LLC',
+ includeDate: false,
+ sourceFiles: false,
+ systemName: 'resumable',
+ theme: 'lumen',
+ default: {
+ outputSourceFiles: false
+ }
+ },
+ markdown: {
+ idInHeadings: true
+ }
+};
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/.nycrc.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/.nycrc.baseline
new file mode 100644
index 000000000000..81a95fc94b00
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/.nycrc.baseline
@@ -0,0 +1,24 @@
+{
+ "report-dir": "./.coverage",
+ "reporter": ["text", "lcov"],
+ "exclude": [
+ "**/*-test",
+ "**/.coverage",
+ "**/apis",
+ "**/benchmark",
+ "**/conformance",
+ "**/docs",
+ "**/samples",
+ "**/scripts",
+ "**/protos",
+ "**/test",
+ "**/*.d.ts",
+ ".jsdoc.js",
+ "**/.jsdoc.js",
+ "karma.conf.js",
+ "webpack-tests.config.js",
+ "webpack.config.js"
+ ],
+ "exclude-after-remap": false,
+ "all": true
+}
\ No newline at end of file
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/README.md.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/README.md.baseline
new file mode 100644
index 000000000000..582e319d972b
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/README.md.baseline
@@ -0,0 +1,108 @@
+[//]: # "This README.md file is auto-generated, all changes to this file will be lost."
+[//]: # "The comments you see below are used to generate those parts of the template in later states."
+
+
+# [Resumable: Nodejs Client][homepage]
+
+[//]: # "releaseLevel"
+
+[](https://www.npmjs.org/package/resumable)
+
+Resumable client for Node.js
+
+[//]: # "partials.introduction"
+
+A comprehensive list of changes in each version may be found in
+[the CHANGELOG][homepage_changelog].
+
+* [Resumable Nodejs Client API Reference](https://cloud.google.com/nodejs/docs/reference/resumable/latest)
+
+
+Read more about the client libraries for Cloud APIs, including the older
+Google APIs Client Libraries, in [Client Libraries Explained][explained].
+
+[explained]: https://cloud.google.com/apis/docs/client-libraries-explained
+
+**Table of contents:**
+
+* [Quickstart](#quickstart)
+ * [Before you begin](#before-you-begin)
+ * [Installing the client library](#installing-the-client-library)
+
+* [Versioning](#versioning)
+* [Contributing](#contributing)
+* [License](#license)
+
+## Quickstart
+### Before you begin
+
+1. [Select or create a Cloud Platform project][projects].
+1. [Enable billing for your project][billing].
+1. [Enable the Resumable API][enable_api].
+1. [Set up authentication][auth] so you can access the
+ API from your local workstation.
+### Installing the client library
+
+```bash
+npm install resumable
+```
+
+[//]: # "partials.body"
+
+## Samples
+
+Samples are in the [`samples/`][homepage_samples] directory. Each sample's `README.md` has instructions for running its sample.
+
+[//]: # "samples"
+
+## Supported Node.js Versions
+
+Our client libraries follow the [Node.js release schedule](https://github.com/nodejs/release#release-schedule).
+Libraries are compatible with all current _active_ and _maintenance_ versions of
+Node.js.
+If you are using an end-of-life version of Node.js, we recommend that you update
+as soon as possible to an actively supported LTS version.
+
+Google's client libraries support legacy versions of Node.js runtimes on a
+best-efforts basis with the following warnings:
+
+* Legacy versions are not tested in continuous integration.
+* Some security patches and features cannot be backported.
+* Dependencies cannot be kept up-to-date.
+
+Client libraries targeting some end-of-life versions of Node.js are available, and
+can be installed through npm [dist-tags](https://docs.npmjs.com/cli/dist-tag).
+The dist-tags follow the naming convention `legacy-(version)`.
+For example, `npm install resumable@legacy-8` installs client libraries
+for versions compatible with Node.js 8.
+
+## Versioning
+
+This library follows [Semantic Versioning](http://semver.org/).
+
+More Information: [Google Cloud Platform Launch Stages][launch_stages]
+
+[launch_stages]: https://cloud.google.com/terms/launch-stages
+
+## Contributing
+
+Contributions welcome! See the [Contributing Guide](https://github.com/googleapis/google-cloud-node/blob/main/CONTRIBUTING.md).
+
+Please note that this `README.md`
+and a variety of configuration files in this repository (including `.nycrc` and `tsconfig.json`)
+are generated from a central template.
+
+## License
+
+Apache Version 2.0
+
+See [LICENSE](https://github.com/googleapis/google-cloud-node/blob/main/LICENSE)
+
+[shell_img]: https://gstatic.com/cloudssh/images/open-btn.png
+[projects]: https://console.cloud.google.com/project
+[billing]: https://support.google.com/cloud/answer/6293499#enable-billing
+[enable_api]: https://console.cloud.google.com/flows/enableapi?apiid=resumable.googleapis.com
+[auth]: https://cloud.google.com/docs/authentication/external/set-up-adc-local
+[homepage_samples]: https://github.com/googleapis/google-cloud-node/blob/main/packages/google-samples-resumable/samples
+[homepage_changelog]: https://github.com/googleapis/google-cloud-node/blob/main/packages/google-samples-resumable/CHANGELOG.md
+[homepage]: https://github.com/googleapis/google-cloud-node/blob/main/packages/google-samples-resumable
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/index.ts.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/index.ts.baseline
new file mode 100644
index 000000000000..3bb734bf4631
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/index.ts.baseline
@@ -0,0 +1,26 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+import * as v1 from './v1/index.js';
+const ResumableUploadServiceClient = v1.ResumableUploadServiceClient;
+type ResumableUploadServiceClient = v1.ResumableUploadServiceClient;
+export {v1, ResumableUploadServiceClient};
+export default {v1, ResumableUploadServiceClient};
+// @ts-ignore
+import * as protos from '../../protos/protos.js';
+export {protos};
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/json-helper.cjs.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/json-helper.cjs.baseline
new file mode 100644
index 000000000000..3c1fc730201e
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/json-helper.cjs.baseline
@@ -0,0 +1,20 @@
+// Copyright 2024 Google LLC
+//
+// Licensed 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.
+
+/* eslint-disable node/no-missing-require */
+function getJSON(path) {
+ return require(path);
+}
+
+exports.getJSON = getJSON;
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/v1/index.ts.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/v1/index.ts.baseline
new file mode 100644
index 000000000000..3659293a6283
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/v1/index.ts.baseline
@@ -0,0 +1,19 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+export {ResumableUploadServiceClient} from './resumable_upload_service_client.js';
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/v1/resumable_upload_service_client.ts.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/v1/resumable_upload_service_client.ts.baseline
new file mode 100644
index 000000000000..c50be8d86055
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/v1/resumable_upload_service_client.ts.baseline
@@ -0,0 +1,623 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+/* global window */
+import * as gax from 'google-gax';
+import type {
+ Callback,
+ CallOptions,
+ Descriptors,
+ ClientOptions,
+} from 'google-gax';
+
+// @ts-ignore
+import type * as protos from '../../../protos/protos.js';
+import * as resumable_upload_service_client_config from './resumable_upload_service_client_config.json';
+import fs from 'fs';
+import path from 'path';
+import {fileURLToPath} from 'url';
+import {getJSON} from '../json-helper.cjs';
+// @ts-ignore
+const dirname = path.dirname(fileURLToPath(import.meta.url));
+
+/**
+ * Client JSON configuration object, loaded from
+ * `src/v1/resumable_upload_service_client_config.json`.
+ * This file defines retry strategy and timeouts for all API methods in this library.
+ */
+const gapicConfig = getJSON(
+ path.join(dirname, 'resumable_upload_service_client_config.json'),
+);
+
+const jsonProtos = getJSON(
+ path.join(dirname, '..', '..', '..', 'protos/protos.json'),
+);
+import {loggingUtils as logging, decodeAnyProtosInArray} from 'google-gax';
+const version = getJSON(
+ path.join(dirname, '..', '..', '..', '..', 'package.json'),
+).version;
+
+/**
+ * @class
+ * @memberof v1
+ */
+export class ResumableUploadServiceClient {
+ private _terminated = false;
+ private _opts: ClientOptions;
+ private _providedCustomServicePath: boolean;
+ private _gaxModule: typeof gax | typeof gax.fallback;
+ private _gaxGrpc: gax.GrpcClient | gax.fallback.GrpcClient;
+ private _fallbackRest?: gax.GrpcClient | gax.fallback.GrpcClient;
+ private _protos: {};
+ private _defaults: {[method: string]: gax.CallSettings};
+ private _universeDomain: string;
+ private _servicePath: string;
+ private _log = logging.log('resumable');
+ auth: gax.GoogleAuth;
+ descriptors: Descriptors = {
+ page: {},
+ stream: {},
+ longrunning: {},
+ batching: {},
+ resumableUpload: {},
+ };
+ warn: (code: string, message: string, warnType?: string) => void;
+ innerApiCalls: {[name: string]: Function};
+ resumableUploadServiceStub?: Promise<{[name: string]: Function}>;
+
+ /**
+ * Construct an instance of ResumableUploadServiceClient.
+ *
+ * @param {object} [options] - The configuration object.
+ * The options accepted by the constructor are described in detail
+ * in [this document](https://github.com/googleapis/gax-nodejs/blob/main/client-libraries.md#creating-the-client-instance).
+ * The common options are:
+ * @param {object} [options.credentials] - Credentials object.
+ * @param {string} [options.credentials.client_email]
+ * @param {string} [options.credentials.private_key]
+ * @param {string} [options.email] - Account email address. Required when
+ * using a .pem or .p12 keyFilename.
+ * @param {string} [options.keyFilename] - Full path to the a .json, .pem, or
+ * .p12 key downloaded from the Google Developers Console. If you provide
+ * a path to a JSON file, the projectId option below is not necessary.
+ * NOTE: .pem and .p12 require you to specify options.email as well.
+ * @param {number} [options.port] - The port on which to connect to
+ * the remote host.
+ * @param {string} [options.projectId] - The project ID from the Google
+ * Developer's Console, e.g. 'grape-spaceship-123'. We will also check
+ * the environment variable GCLOUD_PROJECT for your project ID. If your
+ * app is running in an environment which supports
+ * {@link https://cloud.google.com/docs/authentication/application-default-credentials Application Default Credentials},
+ * your project ID will be detected automatically.
+ * @param {string} [options.apiEndpoint] - The domain name of the
+ * API remote host.
+ * @param {gax.ClientConfig} [options.clientConfig] - Client configuration override.
+ * Follows the structure of {@link gapicConfig}.
+ * @param {boolean | "rest"} [options.fallback] - Use HTTP fallback mode.
+ * Pass "rest" to use HTTP/1.1 REST API instead of gRPC.
+ * For more information, please check the
+ * {@link https://github.com/googleapis/gax-nodejs/blob/main/client-libraries.md#http11-rest-api-mode documentation}.
+ * @param {gax} [gaxInstance]: loaded instance of `google-gax`. Useful if you
+ * need to avoid loading the default gRPC version and want to use the fallback
+ * HTTP implementation. Load only fallback version and pass it to the constructor:
+ * ```
+ * const gax = require('google-gax/build/src/fallback'); // avoids loading google-gax with gRPC
+ * const client = new ResumableUploadServiceClient({fallback: 'rest'}, gax);
+ * ```
+ */
+ constructor(
+ opts?: ClientOptions,
+ gaxInstance?: typeof gax | typeof gax.fallback,
+ ) {
+ // Ensure that options include all the required fields.
+ const staticMembers = this
+ .constructor as typeof ResumableUploadServiceClient;
+ if (
+ opts?.universe_domain &&
+ opts?.universeDomain &&
+ opts?.universe_domain !== opts?.universeDomain
+ ) {
+ throw new Error(
+ 'Please set either universe_domain or universeDomain, but not both.',
+ );
+ }
+ const universeDomainEnvVar =
+ typeof process === 'object' && typeof process.env === 'object'
+ ? process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN']
+ : undefined;
+ this._universeDomain =
+ opts?.universeDomain ??
+ opts?.universe_domain ??
+ universeDomainEnvVar ??
+ 'googleapis.com';
+ this._servicePath = 'resumable.' + this._universeDomain;
+ const servicePath =
+ opts?.servicePath || opts?.apiEndpoint || this._servicePath;
+ this._providedCustomServicePath = !!(
+ opts?.servicePath || opts?.apiEndpoint
+ );
+ const port = opts?.port || staticMembers.port;
+ const clientConfig = opts?.clientConfig ?? {};
+ const fallback =
+ opts?.fallback ??
+ (typeof window !== 'undefined' && typeof window?.fetch === 'function');
+ opts = Object.assign({servicePath, port, clientConfig, fallback}, opts);
+
+ // If scopes are unset in options and we're connecting to a non-default endpoint, set scopes just in case.
+ if (servicePath !== this._servicePath && !('scopes' in opts)) {
+ opts['scopes'] = staticMembers.scopes;
+ }
+
+ // Load google-gax module synchronously if needed
+ if (!gaxInstance) {
+ gaxInstance = gax as typeof gax;
+ }
+
+ // Choose either gRPC or proto-over-HTTP implementation of google-gax.
+ this._gaxModule = opts.fallback ? gaxInstance.fallback : gaxInstance;
+
+ // Create a `gaxGrpc` object, with any grpc-specific options sent to the client.
+ this._gaxGrpc = new this._gaxModule.GrpcClient(opts);
+
+ // This service contains resumable upload methods, which are HTTPS-only.
+ // Make sure the REST transport is available even when the client was
+ // configured for gRPC.
+ this._fallbackRest = opts.fallback
+ ? this._gaxGrpc
+ : new gaxInstance.fallback.GrpcClient({...opts, fallback: true});
+
+ // Save options to use in initialize() method.
+ this._opts = opts;
+
+ // Save the auth object to the client, for use by other methods.
+ this.auth = this._gaxGrpc.auth as gax.GoogleAuth;
+
+ // Set useJWTAccessWithScope on the auth object.
+ this.auth.useJWTAccessWithScope = true;
+
+ // Set defaultServicePath on the auth object.
+ this.auth.defaultServicePath = this._servicePath;
+
+ // Set the default scopes in auth client if needed.
+ if (servicePath === this._servicePath) {
+ this.auth.defaultScopes = staticMembers.scopes;
+ }
+
+ // Add ESM headers
+ const isEsm = true;
+ const isEsmString = isEsm ? '-esm' : '-cjs';
+ // Determine the client header string.
+ const clientHeader = [`gax/${this._gaxModule.version}`, `gapic/${version}`];
+ if (typeof process === 'object' && 'versions' in process) {
+ clientHeader.push(`gl-node/{process.versions.node}${isEsmString}`);
+ } else {
+ clientHeader.push(`gl-web/${this._gaxModule.version}`);
+ }
+ if (!opts.fallback) {
+ clientHeader.push(`grpc/${this._gaxGrpc.grpcVersion}`);
+ } else if (opts.fallback === 'rest') {
+ clientHeader.push(`rest/${this._gaxGrpc.grpcVersion}`);
+ }
+ if (opts.libName && opts.libVersion) {
+ clientHeader.push(`${opts.libName}/${opts.libVersion}`);
+ }
+
+ // Load the applicable protos.
+ this._protos = this._gaxGrpc.loadProtoJSON(
+ jsonProtos as gax.protobuf.INamespace,
+ );
+
+ // Some methods on this API support resumable uploads; provide
+ // descriptors for these methods.
+ this.descriptors.resumableUpload = {
+ createResumableUpload: new this._gaxModule.ResumableUploadDescriptor(
+ '/resumable/upload',
+ ),
+ };
+
+ // Put together the default options sent with requests.
+ this._defaults = this._gaxGrpc.constructSettings(
+ 'google.samples.resumable.v1.ResumableUploadService',
+ gapicConfig as gax.ClientConfig,
+ opts.clientConfig || {},
+ {'x-goog-api-client': clientHeader.join(' ')},
+ );
+
+ // Set up a dictionary of "inner API calls"; the core implementation
+ // of calling the API is handled in `google-gax`, with this code
+ // merely providing the destination and request information.
+ this.innerApiCalls = {};
+
+ // Add a warn function to the client constructor so it can be easily tested.
+ this.warn = this._gaxModule.warn;
+ }
+
+ /**
+ * Initialize the client.
+ * Performs asynchronous operations (such as authentication) and prepares the client.
+ * This function will be called automatically when any class method is called for the
+ * first time, but if you need to initialize it before calling an actual method,
+ * feel free to call initialize() directly.
+ *
+ * You can await on this method if you want to make sure the client is initialized.
+ *
+ * @returns {Promise} A promise that resolves to an authenticated service stub.
+ */
+ initialize() {
+ // If the client stub promise is already initialized, return immediately.
+ if (this.resumableUploadServiceStub) {
+ return this.resumableUploadServiceStub;
+ }
+
+ // Put together the "service stub" for
+ // google.samples.resumable.v1.ResumableUploadService.
+ this.resumableUploadServiceStub = this._gaxGrpc.createStub(
+ this._opts.fallback
+ ? (this._protos as protobuf.Root).lookupService(
+ 'google.samples.resumable.v1.ResumableUploadService',
+ )
+ : // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (this._protos as any).google.samples.resumable.v1
+ .ResumableUploadService,
+ this._opts,
+ this._providedCustomServicePath,
+ ) as Promise<{[method: string]: Function}>;
+
+ // Iterate over each of the methods that the service provides
+ // and create an API call method for each.
+ const resumableUploadServiceStubMethods = ['getUploadStatus'];
+ for (const methodName of resumableUploadServiceStubMethods) {
+ const callPromise = this.resumableUploadServiceStub.then(
+ stub =>
+ (...args: Array<{}>) => {
+ if (this._terminated) {
+ return Promise.reject('The client has already been closed.');
+ }
+ const func = stub[methodName];
+ return func.apply(stub, args);
+ },
+ (err: Error | null | undefined) => () => {
+ throw err;
+ },
+ );
+
+ const descriptor = undefined;
+ const apiCall = this._gaxModule.createApiCall(
+ callPromise,
+ this._defaults[methodName],
+ descriptor,
+ this._opts.fallback,
+ );
+
+ this.innerApiCalls[methodName] = apiCall;
+ }
+
+ // Resumable upload methods do not use the gRPC/REST service stub; the
+ // The ResumableUploadSession performs its own HTTP requests.
+ this.innerApiCalls['createResumableUpload'] = this._gaxModule.createApiCall(
+ this._gaxModule.resumableUploadStub,
+ this._defaults['createResumableUpload'],
+ this.descriptors.resumableUpload!['createResumableUpload'],
+ this._opts.fallback,
+ );
+
+ return this.resumableUploadServiceStub;
+ }
+
+ /**
+ * The DNS address for this API service.
+ * @deprecated Use the apiEndpoint method of the client instance.
+ * @returns {string} The DNS address for this service.
+ */
+ static get servicePath() {
+ if (
+ typeof process === 'object' &&
+ typeof process.emitWarning === 'function'
+ ) {
+ process.emitWarning(
+ 'Static servicePath is deprecated, please use the instance method instead.',
+ 'DeprecationWarning',
+ );
+ }
+ return 'resumable.googleapis.com';
+ }
+
+ /**
+ * The DNS address for this API service - same as servicePath,
+ * exists for compatibility reasons.
+ * @deprecated Use the apiEndpoint method of the client instance.
+ * @returns {string} The DNS address for this service.
+ */
+ static get apiEndpoint() {
+ if (
+ typeof process === 'object' &&
+ typeof process.emitWarning === 'function'
+ ) {
+ process.emitWarning(
+ 'Static apiEndpoint is deprecated, please use the instance method instead.',
+ 'DeprecationWarning',
+ );
+ }
+ return 'resumable.googleapis.com';
+ }
+
+ /**
+ * The DNS address for this API service.
+ * @returns {string} The DNS address for this service.
+ */
+ get apiEndpoint() {
+ return this._servicePath;
+ }
+
+ get universeDomain() {
+ return this._universeDomain;
+ }
+
+ /**
+ * The port for this API service.
+ * @returns {number} The default port for this service.
+ */
+ static get port() {
+ return 443;
+ }
+
+ /**
+ * The scopes needed to make gRPC calls for every method defined
+ * in this service.
+ * @returns {string[]} List of default scopes.
+ */
+ static get scopes() {
+ return ['https://www.googleapis.com/auth/cloud-platform'];
+ }
+
+ getProjectId(): Promise;
+ getProjectId(callback: Callback): void;
+ /**
+ * Return the project ID used by this class.
+ * @returns {Promise} A promise that resolves to string containing the project ID.
+ */
+ getProjectId(
+ callback?: Callback,
+ ): Promise | void {
+ if (callback) {
+ this.auth.getProjectId(callback);
+ return;
+ }
+ return this.auth.getProjectId();
+ }
+
+ // -------------------
+ // -- Service calls --
+ // -------------------
+ /**
+ * Returns the status of a previously created upload session.
+ *
+ * @param {Object} request
+ * The request object that will be sent.
+ * @param {string} request.uploadUrl
+ * @param {object} [options]
+ * Call options. See {@link https://googleapis.dev/nodejs/google-gax/latest/interfaces/CallOptions.html|CallOptions} for more details.
+ * @returns {Promise} - The promise which resolves to an array.
+ * The first element of the array is an object representing {@link protos.google.samples.resumable.v1.GetUploadStatusResponse|GetUploadStatusResponse}.
+ * Please see the {@link https://github.com/googleapis/gax-nodejs/blob/master/client-libraries.md#regular-methods | documentation }
+ * for more details and examples.
+ * @example include:samples/generated/v1/resumable_upload_service.get_upload_status.js
+ * region_tag:resumable_v1_generated_ResumableUploadService_GetUploadStatus_async
+ */
+ getUploadStatus(
+ request?: protos.google.samples.resumable.v1.IGetUploadStatusRequest,
+ options?: CallOptions,
+ ): Promise<
+ [
+ protos.google.samples.resumable.v1.IGetUploadStatusResponse,
+ protos.google.samples.resumable.v1.IGetUploadStatusRequest | undefined,
+ {} | undefined,
+ ]
+ >;
+ getUploadStatus(
+ request: protos.google.samples.resumable.v1.IGetUploadStatusRequest,
+ options: CallOptions,
+ callback: Callback<
+ protos.google.samples.resumable.v1.IGetUploadStatusResponse,
+ | protos.google.samples.resumable.v1.IGetUploadStatusRequest
+ | null
+ | undefined,
+ {} | null | undefined
+ >,
+ ): void;
+ getUploadStatus(
+ request: protos.google.samples.resumable.v1.IGetUploadStatusRequest,
+ callback: Callback<
+ protos.google.samples.resumable.v1.IGetUploadStatusResponse,
+ | protos.google.samples.resumable.v1.IGetUploadStatusRequest
+ | null
+ | undefined,
+ {} | null | undefined
+ >,
+ ): void;
+ getUploadStatus(
+ request?: protos.google.samples.resumable.v1.IGetUploadStatusRequest,
+ optionsOrCallback?:
+ | CallOptions
+ | Callback<
+ protos.google.samples.resumable.v1.IGetUploadStatusResponse,
+ | protos.google.samples.resumable.v1.IGetUploadStatusRequest
+ | null
+ | undefined,
+ {} | null | undefined
+ >,
+ callback?: Callback<
+ protos.google.samples.resumable.v1.IGetUploadStatusResponse,
+ | protos.google.samples.resumable.v1.IGetUploadStatusRequest
+ | null
+ | undefined,
+ {} | null | undefined
+ >,
+ ): Promise<
+ [
+ protos.google.samples.resumable.v1.IGetUploadStatusResponse,
+ protos.google.samples.resumable.v1.IGetUploadStatusRequest | undefined,
+ {} | undefined,
+ ]
+ > | void {
+ request = request || {};
+ let options: CallOptions;
+ if (typeof optionsOrCallback === 'function' && callback === undefined) {
+ callback = optionsOrCallback;
+ options = {};
+ } else {
+ options = optionsOrCallback as CallOptions;
+ }
+ options = options || {};
+ options.otherArgs = options.otherArgs || {};
+ options.otherArgs.headers = options.otherArgs.headers || {};
+ options.otherArgs.headers['x-goog-request-params'] =
+ this._gaxModule.routingHeader.fromParams({
+ upload_url: request.uploadUrl ?? '',
+ });
+ this.initialize().catch(err => {
+ throw err;
+ });
+ this._log.info('getUploadStatus request %j', request);
+ const wrappedCallback:
+ | Callback<
+ protos.google.samples.resumable.v1.IGetUploadStatusResponse,
+ | protos.google.samples.resumable.v1.IGetUploadStatusRequest
+ | null
+ | undefined,
+ {} | null | undefined
+ >
+ | undefined = callback
+ ? (error, response, options, rawResponse) => {
+ this._log.info('getUploadStatus response %j', response);
+ callback!(error, response, options, rawResponse);
+ }
+ : undefined;
+ return this.innerApiCalls
+ .getUploadStatus(request, options, wrappedCallback)
+ ?.then(
+ ([response, options, rawResponse]: [
+ protos.google.samples.resumable.v1.IGetUploadStatusResponse,
+ (
+ | protos.google.samples.resumable.v1.IGetUploadStatusRequest
+ | undefined
+ ),
+ {} | undefined,
+ ]) => {
+ this._log.info('getUploadStatus response %j', response);
+ return [response, options, rawResponse];
+ },
+ )
+ .catch((error: any) => {
+ if (
+ error &&
+ 'statusDetails' in error &&
+ error.statusDetails instanceof Array
+ ) {
+ const protos = this._gaxModule.protobuf.Root.fromJSON(
+ jsonProtos,
+ ) as unknown as gax.protobuf.Type;
+ error.statusDetails = decodeAnyProtosInArray(
+ error.statusDetails,
+ protos,
+ );
+ }
+ throw error;
+ });
+ }
+ /**
+ * Creates a {@link gax.ResumableSource} backed by a local file.
+ *
+ * This delegates to google-gax so generated clients do not depend on the
+ * Node.js `fs` module at import time. The source can be passed as the
+ * `uploadSource` parameter of {@link gax.ResumableUploadSession#start}.
+ *
+ * @param {string} filePath - Path to the local file to upload.
+ * @returns {gax.ResumableSource} A seekable upload source for the file.
+ */
+ getResumableSource(filePath: string): gax.ResumableSource {
+ const gaxModule = this._gaxModule as typeof gax;
+ return gaxModule.resumableSourceFromFile(filePath);
+ }
+ /**
+ * Creates a resumable upload session.
+ *
+ * @param {object} [request] - The request object.
+ * @param {object} [options] - Optional parameters. The upload source, chunk
+ * size, progress callback, and resume URL are passed to
+ * {@link gax.ResumableUploadSession#start} instead.
+ * @returns {Promise} A resumable upload session.
+ * Call `.start(uploadParams)` with the source to upload, then await
+ * `.finished()` for the final RPC response.
+ */
+ createResumableUpload(
+ request?: protos.google.samples.resumable.v1.ICreateResumableUploadRequest,
+ options?: CallOptions,
+ ): Promise {
+ request = request || {};
+ options = options || {};
+ if (!this._opts.fallback && this._opts.sslCreds) {
+ return Promise.reject(
+ new this._gaxModule.GoogleError(
+ 'Resumable upload methods require HTTP(S) authentication and ' +
+ 'cannot be used with gRPC channel credentials. Configure the ' +
+ 'client without `sslCreds`, or use `fallback: true`.',
+ ),
+ );
+ }
+ this.initialize().catch(err => {
+ throw err;
+ });
+ this._log.info('createResumableUpload request %j', request);
+ return (
+ this.innerApiCalls['createResumableUpload'](request, {
+ ...options,
+ resumableUpload: {
+ auth: this._fallbackRest!.auth as gax.GoogleAuth,
+ servicePath: this._opts.servicePath ?? this._servicePath,
+ servicePort: this._opts.port || 443,
+ protocol: this._opts.protocol || 'https',
+ rpc: this._gaxModule.protobuf.Root.fromJSON(jsonProtos).lookupService(
+ 'google.samples.resumable.v1.ResumableUploadService',
+ ).methods['CreateResumableUpload'],
+ request,
+ uploadPrefix: '/resumable/upload',
+ numericEnums: this._opts.numericEnums,
+ minifyJson: this._opts.minifyJson,
+ },
+ }) as Promise<[gax.ResumableUploadSession]>
+ ).then(([session]) => session);
+ }
+
+ /**
+ * Terminate the gRPC channel and close the client.
+ *
+ * The client will no longer be usable and all future behavior is undefined.
+ * @returns {Promise} A promise that resolves when the client is closed.
+ */
+ close(): Promise {
+ if (this.resumableUploadServiceStub && !this._terminated) {
+ return this.resumableUploadServiceStub.then(stub => {
+ this._log.info('ending gRPC channel');
+ this._terminated = true;
+ stub.close();
+ });
+ }
+ return Promise.resolve();
+ }
+}
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/v1/resumable_upload_service_client_config.json.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/v1/resumable_upload_service_client_config.json.baseline
new file mode 100644
index 000000000000..de3f9fed6441
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/v1/resumable_upload_service_client_config.json.baseline
@@ -0,0 +1,34 @@
+{
+ "interfaces": {
+ "google.samples.resumable.v1.ResumableUploadService": {
+ "retry_codes": {
+ "non_idempotent": [],
+ "idempotent": [
+ "DEADLINE_EXCEEDED",
+ "UNAVAILABLE"
+ ]
+ },
+ "retry_params": {
+ "default": {
+ "initial_retry_delay_millis": 100,
+ "retry_delay_multiplier": 1.3,
+ "max_retry_delay_millis": 60000,
+ "initial_rpc_timeout_millis": 60000,
+ "rpc_timeout_multiplier": 1,
+ "max_rpc_timeout_millis": 60000,
+ "total_timeout_millis": 600000
+ }
+ },
+ "methods": {
+ "CreateResumableUpload": {
+ "retry_codes_name": "non_idempotent",
+ "retry_params_name": "default"
+ },
+ "GetUploadStatus": {
+ "retry_codes_name": "non_idempotent",
+ "retry_params_name": "default"
+ }
+ }
+ }
+ }
+}
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/v1/resumable_upload_service_proto_list.json.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/v1/resumable_upload_service_proto_list.json.baseline
new file mode 100644
index 000000000000..4acc3ac38ace
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/src/v1/resumable_upload_service_proto_list.json.baseline
@@ -0,0 +1,3 @@
+[
+ "../../protos/google/samples/resumable/v1/resumable.proto"
+]
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/system-test/fixtures/sample/src/index.cjs.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/system-test/fixtures/sample/src/index.cjs.baseline
new file mode 100644
index 000000000000..0bad3604de88
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/system-test/fixtures/sample/src/index.cjs.baseline
@@ -0,0 +1,27 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+
+/* eslint-disable node/no-missing-require, no-unused-vars, no-undef */
+const resumable = require('resumable');
+
+function main() {
+ const resumableUploadServiceClient = new resumable.ResumableUploadServiceClient();
+}
+
+main();
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/system-test/fixtures/sample/src/index.js.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/system-test/fixtures/sample/src/index.js.baseline
new file mode 100644
index 000000000000..db497b0f574d
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/system-test/fixtures/sample/src/index.js.baseline
@@ -0,0 +1,27 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+
+/* eslint-disable node/no-missing-require, no-unused-vars, no-undef */
+import * as resumable from 'resumable';
+
+function main() {
+ const resumableUploadServiceClient = new resumable.ResumableUploadServiceClient();
+}
+
+main();
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/system-test/fixtures/sample/src/index.ts.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/system-test/fixtures/sample/src/index.ts.baseline
new file mode 100644
index 000000000000..7320067b9a2b
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/system-test/fixtures/sample/src/index.ts.baseline
@@ -0,0 +1,35 @@
+/* eslint-disable node/no-missing-require, no-unused-vars, no-undef */
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+import {ResumableUploadServiceClient} from 'resumable';
+
+// check that the client class type name can be used
+function doStuffWithResumableUploadServiceClient(
+ client: ResumableUploadServiceClient,
+) {
+ client.close();
+}
+
+function main() {
+ // check that the client instance can be created
+ const resumableUploadServiceClient = new ResumableUploadServiceClient();
+ doStuffWithResumableUploadServiceClient(resumableUploadServiceClient);
+}
+
+main();
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/system-test/install.ts.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/system-test/install.ts.baseline
new file mode 100644
index 000000000000..77ea836f8af2
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/system-test/install.ts.baseline
@@ -0,0 +1,60 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+import {packNTest} from 'pack-n-play';
+import {readFileSync} from 'fs';
+import {describe, it} from 'mocha';
+
+describe('📦 pack-n-play test', () => {
+ it('TypeScript', async function () {
+ this.timeout(300000);
+ await packNTest({
+ packageDir: process.cwd(),
+ sample: {
+ description: 'TypeScript user can use the type definitions',
+ ts: readFileSync(
+ './esm/system-test/fixtures/sample/src/index.ts',
+ ).toString(),
+ },
+ });
+ });
+
+ it('ESM module', async function () {
+ this.timeout(300000);
+ await packNTest({
+ sample: {
+ description: 'Should be able to import using ESM',
+ esm: readFileSync(
+ './esm/system-test/fixtures/sample/src/index.js',
+ ).toString(),
+ },
+ });
+ });
+
+ it('CJS module', async function () {
+ this.timeout(300000);
+ await packNTest({
+ sample: {
+ description: 'Should be able to import using CJS',
+ cjs: readFileSync(
+ './esm/system-test/fixtures/sample/src/index.cjs',
+ ).toString(),
+ },
+ });
+ });
+});
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/test/gapic_resumable_upload_service_v1.ts.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/test/gapic_resumable_upload_service_v1.ts.baseline
new file mode 100644
index 000000000000..f9fdbf6e2ce8
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/esm/test/gapic_resumable_upload_service_v1.ts.baseline
@@ -0,0 +1,419 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+// @ts-ignore
+import * as protos from '../../protos/protos.js';
+import assert from 'assert';
+import * as sinon from 'sinon';
+import {SinonStub} from 'sinon';
+import {describe, it} from 'mocha';
+import * as resumableuploadserviceModule from '../src/index.js';
+
+import {protobuf} from 'google-gax';
+import fs from 'fs';
+import path from 'path';
+import {fileURLToPath} from 'url';
+
+// @ts-ignore
+const dirname = path.dirname(fileURLToPath(import.meta.url));
+// Dynamically loaded proto JSON is needed to get the type information
+// to fill in default values for request objects
+const root = protobuf.Root.fromJSON(
+ JSON.parse(
+ fs.readFileSync(
+ path.join(dirname, '..', '..', 'protos/protos.json'),
+ 'utf8',
+ ),
+ ),
+);
+
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+function getTypeDefaultValue(typeName: string, fields: string[]) {
+ let type = root.lookupType(typeName) as protobuf.Type;
+ for (const field of fields.slice(0, -1)) {
+ type = type?.fields[field]?.resolvedType as protobuf.Type;
+ }
+ return type?.fields[fields[fields.length - 1]]?.defaultValue ?? null;
+}
+
+function generateSampleMessage(instance: T) {
+ const filledObject = (
+ instance.constructor as typeof protobuf.Message
+ ).toObject(instance as protobuf.Message, {defaults: true});
+ return (instance.constructor as typeof protobuf.Message).fromObject(
+ filledObject,
+ ) as T;
+}
+
+function stubSimpleCall(response?: ResponseType, error?: Error) {
+ return error
+ ? sinon.stub().rejects(error)
+ : sinon.stub().resolves([response]);
+}
+
+function stubSimpleCallWithCallback(
+ response?: ResponseType,
+ error?: Error,
+) {
+ return error
+ ? sinon.stub().callsArgWith(2, error)
+ : sinon.stub().callsArgWith(2, null, response);
+}
+
+describe('v1.ResumableUploadServiceClient', () => {
+ describe('Common methods', () => {
+ it('has apiEndpoint', () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient();
+ const apiEndpoint = client.apiEndpoint;
+ assert.strictEqual(apiEndpoint, 'resumable.googleapis.com');
+ });
+
+ it('has universeDomain', () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient();
+ const universeDomain = client.universeDomain;
+ assert.strictEqual(universeDomain, 'googleapis.com');
+ });
+
+ if (
+ typeof process === 'object' &&
+ typeof process.emitWarning === 'function'
+ ) {
+ it('throws DeprecationWarning if static servicePath is used', () => {
+ const stub = sinon.stub(process, 'emitWarning');
+ const servicePath =
+ resumableuploadserviceModule.v1.ResumableUploadServiceClient
+ .servicePath;
+ assert.strictEqual(servicePath, 'resumable.googleapis.com');
+ assert(stub.called);
+ stub.restore();
+ });
+
+ it('throws DeprecationWarning if static apiEndpoint is used', () => {
+ const stub = sinon.stub(process, 'emitWarning');
+ const apiEndpoint =
+ resumableuploadserviceModule.v1.ResumableUploadServiceClient
+ .apiEndpoint;
+ assert.strictEqual(apiEndpoint, 'resumable.googleapis.com');
+ assert(stub.called);
+ stub.restore();
+ });
+ }
+ it('sets apiEndpoint according to universe domain camelCase', () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ universeDomain: 'example.com',
+ });
+ const servicePath = client.apiEndpoint;
+ assert.strictEqual(servicePath, 'resumable.example.com');
+ });
+
+ it('sets apiEndpoint according to universe domain snakeCase', () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ universe_domain: 'example.com',
+ });
+ const servicePath = client.apiEndpoint;
+ assert.strictEqual(servicePath, 'resumable.example.com');
+ });
+
+ if (typeof process === 'object' && 'env' in process) {
+ describe('GOOGLE_CLOUD_UNIVERSE_DOMAIN environment variable', () => {
+ it('sets apiEndpoint from environment variable', () => {
+ const saved = process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'];
+ process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'] = 'example.com';
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient();
+ const servicePath = client.apiEndpoint;
+ assert.strictEqual(servicePath, 'resumable.example.com');
+ if (saved) {
+ process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'] = saved;
+ } else {
+ delete process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'];
+ }
+ });
+
+ it('value configured in code has priority over environment variable', () => {
+ const saved = process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'];
+ process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'] = 'example.com';
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ universeDomain: 'configured.example.com',
+ });
+ const servicePath = client.apiEndpoint;
+ assert.strictEqual(servicePath, 'resumable.configured.example.com');
+ if (saved) {
+ process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'] = saved;
+ } else {
+ delete process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'];
+ }
+ });
+ });
+ }
+ it('does not allow setting both universeDomain and universe_domain', () => {
+ assert.throws(() => {
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ universe_domain: 'example.com',
+ universeDomain: 'example.net',
+ });
+ });
+ });
+
+ it('has port', () => {
+ const port =
+ resumableuploadserviceModule.v1.ResumableUploadServiceClient.port;
+ assert(port);
+ assert(typeof port === 'number');
+ });
+
+ it('should create a client with no option', () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient();
+ assert(client);
+ });
+
+ it('should create a client with gRPC fallback', () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ fallback: true,
+ });
+ assert(client);
+ });
+
+ it('has initialize method and supports deferred initialization', async () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ assert.strictEqual(client.resumableUploadServiceStub, undefined);
+ await client.initialize();
+ assert(client.resumableUploadServiceStub);
+ });
+
+ it('has close method for the initialized client', done => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ client.initialize().catch(err => {
+ throw err;
+ });
+ assert(client.resumableUploadServiceStub);
+ client
+ .close()
+ .then(() => {
+ done();
+ })
+ .catch(err => {
+ throw err;
+ });
+ });
+
+ it('has close method for the non-initialized client', done => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ assert.strictEqual(client.resumableUploadServiceStub, undefined);
+ client
+ .close()
+ .then(() => {
+ done();
+ })
+ .catch(err => {
+ throw err;
+ });
+ });
+
+ it('has getProjectId method', async () => {
+ const fakeProjectId = 'fake-project-id';
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ client.auth.getProjectId = sinon.stub().resolves(fakeProjectId);
+ const result = await client.getProjectId();
+ assert.strictEqual(result, fakeProjectId);
+ assert((client.auth.getProjectId as SinonStub).calledWithExactly());
+ });
+
+ it('has getProjectId method with callback', async () => {
+ const fakeProjectId = 'fake-project-id';
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ client.auth.getProjectId = sinon
+ .stub()
+ .callsArgWith(0, null, fakeProjectId);
+ const promise = new Promise((resolve, reject) => {
+ client.getProjectId((err?: Error | null, projectId?: string | null) => {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(projectId);
+ }
+ });
+ });
+ const result = await promise;
+ assert.strictEqual(result, fakeProjectId);
+ });
+ });
+
+ describe('getUploadStatus', () => {
+ it('invokes getUploadStatus without error', async () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ await client.initialize();
+ const request = generateSampleMessage(
+ new protos.google.samples.resumable.v1.GetUploadStatusRequest(),
+ );
+ const defaultValue1 = getTypeDefaultValue(
+ '.google.samples.resumable.v1.GetUploadStatusRequest',
+ ['uploadUrl'],
+ );
+ request.uploadUrl = defaultValue1;
+ const expectedHeaderRequestParams = `upload_url=${defaultValue1 ?? ''}`;
+ const expectedResponse = generateSampleMessage(
+ new protos.google.samples.resumable.v1.GetUploadStatusResponse(),
+ );
+ client.innerApiCalls.getUploadStatus = stubSimpleCall(expectedResponse);
+ const [response] = await client.getUploadStatus(request);
+ assert.deepStrictEqual(response, expectedResponse);
+ const actualRequest = (
+ client.innerApiCalls.getUploadStatus as SinonStub
+ ).getCall(0).args[0];
+ assert.deepStrictEqual(actualRequest, request);
+ const actualHeaderRequestParams = (
+ client.innerApiCalls.getUploadStatus as SinonStub
+ ).getCall(0).args[1].otherArgs.headers['x-goog-request-params'];
+ assert(actualHeaderRequestParams.includes(expectedHeaderRequestParams));
+ });
+
+ it('invokes getUploadStatus without error using callback', async () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ await client.initialize();
+ const request = generateSampleMessage(
+ new protos.google.samples.resumable.v1.GetUploadStatusRequest(),
+ );
+ const defaultValue1 = getTypeDefaultValue(
+ '.google.samples.resumable.v1.GetUploadStatusRequest',
+ ['uploadUrl'],
+ );
+ request.uploadUrl = defaultValue1;
+ const expectedHeaderRequestParams = `upload_url=${defaultValue1 ?? ''}`;
+ const expectedResponse = generateSampleMessage(
+ new protos.google.samples.resumable.v1.GetUploadStatusResponse(),
+ );
+ client.innerApiCalls.getUploadStatus =
+ stubSimpleCallWithCallback(expectedResponse);
+ const promise = new Promise((resolve, reject) => {
+ client.getUploadStatus(
+ request,
+ (
+ err?: Error | null,
+ result?: protos.google.samples.resumable.v1.IGetUploadStatusResponse | null,
+ ) => {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(result);
+ }
+ },
+ );
+ });
+ const response = await promise;
+ assert.deepStrictEqual(response, expectedResponse);
+ const actualRequest = (
+ client.innerApiCalls.getUploadStatus as SinonStub
+ ).getCall(0).args[0];
+ assert.deepStrictEqual(actualRequest, request);
+ const actualHeaderRequestParams = (
+ client.innerApiCalls.getUploadStatus as SinonStub
+ ).getCall(0).args[1].otherArgs.headers['x-goog-request-params'];
+ assert(actualHeaderRequestParams.includes(expectedHeaderRequestParams));
+ });
+
+ it('invokes getUploadStatus with error', async () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ await client.initialize();
+ const request = generateSampleMessage(
+ new protos.google.samples.resumable.v1.GetUploadStatusRequest(),
+ );
+ const defaultValue1 = getTypeDefaultValue(
+ '.google.samples.resumable.v1.GetUploadStatusRequest',
+ ['uploadUrl'],
+ );
+ request.uploadUrl = defaultValue1;
+ const expectedHeaderRequestParams = `upload_url=${defaultValue1 ?? ''}`;
+ const expectedError = new Error('expected');
+ client.innerApiCalls.getUploadStatus = stubSimpleCall(
+ undefined,
+ expectedError,
+ );
+ await assert.rejects(client.getUploadStatus(request), expectedError);
+ const actualRequest = (
+ client.innerApiCalls.getUploadStatus as SinonStub
+ ).getCall(0).args[0];
+ assert.deepStrictEqual(actualRequest, request);
+ const actualHeaderRequestParams = (
+ client.innerApiCalls.getUploadStatus as SinonStub
+ ).getCall(0).args[1].otherArgs.headers['x-goog-request-params'];
+ assert(actualHeaderRequestParams.includes(expectedHeaderRequestParams));
+ });
+
+ it('invokes getUploadStatus with closed client', async () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ await client.initialize();
+ const request = generateSampleMessage(
+ new protos.google.samples.resumable.v1.GetUploadStatusRequest(),
+ );
+ const defaultValue1 = getTypeDefaultValue(
+ '.google.samples.resumable.v1.GetUploadStatusRequest',
+ ['uploadUrl'],
+ );
+ request.uploadUrl = defaultValue1;
+ const expectedError = new Error('The client has already been closed.');
+ client.close().catch(err => {
+ throw err;
+ });
+ await assert.rejects(client.getUploadStatus(request), expectedError);
+ });
+ });
+});
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/package.json b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/package.json
new file mode 100644
index 000000000000..ac4f9bc1f502
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/package.json
@@ -0,0 +1,108 @@
+{
+ "name": "resumable",
+ "version": "0.1.0",
+ "description": "Resumable client for Node.js",
+ "repository": {
+ "type": "git",
+ "directory": "packages/google-samples-resumable",
+ "url": "https://github.com/googleapis/google-cloud-node.git"
+ },
+ "license": "Apache-2.0",
+ "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-samples-resumable",
+ "author": "Google LLC",
+ "main": "./build/cjs/src/index.cjs",
+ "types": "./build/cjs/src/index.d.ts",
+ "type": "module",
+ "exports": {
+ ".": {
+ "import": {
+ "types": "./build/esm/src/index.d.ts",
+ "default": "./build/esm/src/index.js"
+ },
+ "require": {
+ "types": "./build/cjs/src/index.d.ts",
+ "default": "./build/cjs/src/index.cjs"
+ }
+ },
+ "./build/protos/protos": {
+ "import": {
+ "types": "./build/protos/protos/protos.d.ts",
+ "default": "./build/protos/protos/protos.js"
+ },
+ "require": {
+ "types": "./build/protos/protos/protos.d.ts",
+ "default": "./build/protos/protos/protos.cjs"
+ }
+ }
+ },
+ "files": [
+ "build/esm",
+ "build/cjs",
+ "build/protos",
+ "!build/esm/**/*.map",
+ "!build/cjs/**/*.map"
+ ],
+ "keywords": [
+ "google apis client",
+ "google api client",
+ "google apis",
+ "google api",
+ "google",
+ "google cloud platform",
+ "google cloud",
+ "cloud",
+ "google resumable",
+ "resumable",
+ "resumable upload service"
+ ],
+ "scripts": {
+ "clean": "gts clean",
+ "compile-protos": "compileProtos esm/src --esm ",
+ "docs": "jsdoc -c .jsdoc.cjs",
+ "postpack": "minifyProtoJson build/cjs && minifyProtoJson build/esm",
+ "fix": "gts fix",
+ "lint": "gts check",
+ "prepare": "npm run compile-protos && npm run compile",
+ "system-test:cjs": "c8 mocha --config ../../.mocharc.cjs --no-parallel build/cjs/system-test",
+ "system-test:esm": "c8 mocha --config ../../.mocharc.cjs --no-parallel build/esm/system-test",
+ "system-test": "npm run system-test:esm && npm run system-test:cjs",
+ "test:cjs": "c8 mocha --config ../../.mocharc.cjs build/cjs/test",
+ "test:esm": "c8 mocha --config ../../.mocharc.cjs build/esm/test",
+ "test": "npm run test:cjs && npm run test:esm",
+ "compile:esm": "tsc -p ./tsconfig.esm.json && cp -r esm/src/json-helper.cjs build/esm/src/json-helper.cjs",
+ "babel": "babel esm --out-dir build/cjs --ignore \"esm/**/*.d.ts\" --extensions \".ts\" --out-file-extension .cjs --copy-files",
+ "compile:cjs": "tsc -p ./tsconfig.json && npm run babel",
+ "compile": "npm run compile:esm && rm -rf esm/src/json-helper.d.cts && npm run compile:cjs && rm -rf build/protos && cp -r protos build/protos",
+ "samples-test": "cd samples/ && npm link ../ && npm i && npm test"
+ },
+ "dependencies": {
+ "google-gax": "^6.0.0"
+ },
+ "devDependencies": {
+ "@babel/cli": "^7.28.3",
+ "@babel/core": "^7.28.5",
+ "@babel/preset-env": "^7.28.5",
+ "@babel/preset-typescript": "^7.28.5",
+ "@types/mocha": "^10.0.10",
+ "@types/node": "^22.18.12",
+ "@types/sinon": "^20.0.0",
+ "babel-plugin-replace-import-extension": "^1.1.5",
+ "c8": "^10.1.3",
+ "gapic-tools": "^2.0.0",
+ "gts": "^6.0.2",
+ "jsdoc": "^4.0.5",
+ "jsdoc-region-tag": "^5.0.0",
+ "jsdoc-fresh": "^6.0.0",
+ "long": "^5.3.2",
+ "mocha": "^11.7.4",
+ "typescript": "5.8.3",
+ "pack-n-play": "^5.0.0",
+ "sinon": "^20.0.0",
+ "ts-loader": "^8.4.0",
+ "webpack": "^5.102.1",
+ "webpack-cli": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=22"
+ }
+}
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/package.json.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/package.json.baseline
new file mode 120000
index 000000000000..2ff8622f1722
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/package.json.baseline
@@ -0,0 +1 @@
+package.json
\ No newline at end of file
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/protos/google/samples/resumable/v1/resumable.proto.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/protos/google/samples/resumable/v1/resumable.proto.baseline
new file mode 100644
index 000000000000..c5980d756f9d
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/protos/google/samples/resumable/v1/resumable.proto.baseline
@@ -0,0 +1,72 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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.
+
+// Synthetic fixture used by the baseline tests to exercise resumable upload
+// method generation via the resumable_upload_methods generator parameter.
+
+syntax = "proto3";
+
+package google.samples.resumable.v1;
+
+import "google/api/annotations.proto";
+import "google/api/client.proto";
+
+option csharp_namespace = "Google.Samples.Resumable.V1";
+option go_package = "google.golang.org/genproto/googleapis/samples/resumable/v1;resumable";
+option java_multiple_files = true;
+option java_outer_classname = "ResumableProto";
+option java_package = "com.google.samples.resumable.v1";
+option php_namespace = "Google\\Samples\\Resumable\\V1";
+option ruby_package = "Google::Samples::Resumable::V1";
+
+service ResumableUploadService {
+ option (google.api.default_host) = "resumable.googleapis.com";
+ option (google.api.oauth_scopes) =
+ "https://www.googleapis.com/auth/cloud-platform";
+
+ // Creates a resumable upload session.
+ rpc CreateResumableUpload(CreateResumableUploadRequest)
+ returns (CreateResumableUploadResponse) {
+ option (google.api.http) = {
+ post: "/v1/uploads"
+ body: "*"
+ };
+ }
+
+ // Returns the status of a previously created upload session.
+ rpc GetUploadStatus(GetUploadStatusRequest)
+ returns (GetUploadStatusResponse) {
+ option (google.api.http) = {
+ get: "/v1/uploads/{upload_url}"
+ };
+ }
+}
+
+message CreateResumableUploadRequest {
+ string name = 1;
+ string description = 2;
+}
+
+message CreateResumableUploadResponse {
+ string upload_url = 1;
+ string status = 2;
+}
+
+message GetUploadStatusRequest {
+ string upload_url = 1;
+}
+
+message GetUploadStatusResponse {
+ string status = 1;
+}
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/samples/generated/v1/resumable_upload_service.create_resumable_upload.js.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/samples/generated/v1/resumable_upload_service.create_resumable_upload.js.baseline
new file mode 100644
index 000000000000..67188e48e219
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/samples/generated/v1/resumable_upload_service.create_resumable_upload.js.baseline
@@ -0,0 +1,65 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+
+
+'use strict';
+
+function main() {
+ // [START resumable_v1_generated_ResumableUploadService_CreateResumableUpload_async]
+ /**
+ * This snippet has been automatically generated and should be regarded as a code template only.
+ * It will require modifications to work.
+ * It may require correct/in-range values for request initialization.
+ * TODO(developer): Uncomment these variables before running the sample.
+ */
+ /**
+ */
+ // const name = 'abc123'
+ /**
+ */
+ // const description = 'abc123'
+
+ // Imports the Resumable library
+ const {ResumableUploadServiceClient} = require('resumable').v1;
+
+ // Instantiates a client
+ const resumableClient = new ResumableUploadServiceClient();
+
+ async function callCreateResumableUpload() {
+ // Construct request
+ const request = {
+ };
+
+ // Run request
+ const session = await resumableClient.createResumableUpload(request);
+ const uploadSource = resumableClient.getResumableSource('/path/to/file');
+ await session.start({uploadSource});
+ const response = await session.finished();
+ console.log(response);
+ }
+
+ callCreateResumableUpload();
+ // [END resumable_v1_generated_ResumableUploadService_CreateResumableUpload_async]
+}
+
+process.on('unhandledRejection', err => {
+ console.error(err.message);
+ process.exitCode = 1;
+});
+main(...process.argv.slice(2));
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/samples/generated/v1/resumable_upload_service.get_upload_status.js.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/samples/generated/v1/resumable_upload_service.get_upload_status.js.baseline
new file mode 100644
index 000000000000..1bc4435b7075
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/samples/generated/v1/resumable_upload_service.get_upload_status.js.baseline
@@ -0,0 +1,59 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+
+
+'use strict';
+
+function main() {
+ // [START resumable_v1_generated_ResumableUploadService_GetUploadStatus_async]
+ /**
+ * This snippet has been automatically generated and should be regarded as a code template only.
+ * It will require modifications to work.
+ * It may require correct/in-range values for request initialization.
+ * TODO(developer): Uncomment these variables before running the sample.
+ */
+ /**
+ */
+ // const uploadUrl = 'abc123'
+
+ // Imports the Resumable library
+ const {ResumableUploadServiceClient} = require('resumable').v1;
+
+ // Instantiates a client
+ const resumableClient = new ResumableUploadServiceClient();
+
+ async function callGetUploadStatus() {
+ // Construct request
+ const request = {
+ };
+
+ // Run request
+ const response = await resumableClient.getUploadStatus(request);
+ console.log(response);
+ }
+
+ callGetUploadStatus();
+ // [END resumable_v1_generated_ResumableUploadService_GetUploadStatus_async]
+}
+
+process.on('unhandledRejection', err => {
+ console.error(err.message);
+ process.exitCode = 1;
+});
+main(...process.argv.slice(2));
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/tsconfig.esm.json.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/tsconfig.esm.json.baseline
new file mode 100644
index 000000000000..9ea46f074fa2
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/tsconfig.esm.json.baseline
@@ -0,0 +1,27 @@
+{
+ "extends": "./node_modules/gts/tsconfig-google.json",
+ "compilerOptions": {
+ "rootDir": ".",
+ "outDir": "build",
+ "resolveJsonModule": true,
+ "module": "es2020",
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "sourceMap": false,
+ "allowJs": true,
+ "lib": [
+ "es2020",
+ "DOM"
+ ]
+ },
+ "include": [
+ "esm/src/*.ts",
+ "esm/src/**/*.ts",
+ "esm/test/*.ts",
+ "esm/test/**/*.ts",
+ "esm/system-test/*.ts",
+ "esm/src/**/*.json",
+ "protos/protos.json",
+ "esm/src/*.cjs"
+ ]
+}
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/tsconfig.json.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/tsconfig.json.baseline
new file mode 100644
index 000000000000..110f6eccd41b
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/tsconfig.json.baseline
@@ -0,0 +1,32 @@
+{
+ "extends": "./node_modules/gts/tsconfig-google.json",
+ "compilerOptions": {
+ "rootDir": ".",
+ "resolveJsonModule": true,
+ "moduleResolution": "node",
+ "allowJs": true,
+ "esModuleInterop": true,
+ "sourceMap": false,
+ "target": "esnext",
+ "module": "CommonJS",
+ "declaration": true,
+ "strict": true,
+ "isolatedModules": false,
+ "emitDeclarationOnly": true,
+ "lib": [
+ "es2023",
+ "dom"
+ ]
+ },
+ "include": [
+ "esm/src/*.ts",
+ "esm/src/**/*.ts",
+ "esm/test/*.ts",
+ "esm/test/**/*.ts",
+ "esm/src/**/*.json",
+ "esm/system-test/*.ts",
+ "esm/src/*.cjs",
+ "samples/**/*.json",
+ "protos/protos.json"
+ ]
+}
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/webpack.config.cjs.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/webpack.config.cjs.baseline
new file mode 100644
index 000000000000..0a553e060843
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload-esm/webpack.config.cjs.baseline
@@ -0,0 +1,64 @@
+// Copyright 2021 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+
+const path = require('path');
+
+module.exports = {
+ entry: './src/index.ts',
+ output: {
+ library: 'ResumableUploadService',
+ filename: './resumable-upload-service.js',
+ },
+ node: {
+ child_process: 'empty',
+ fs: 'empty',
+ crypto: 'empty',
+ },
+ resolve: {
+ alias: {
+ '../../../package.json': path.resolve(__dirname, 'package.json'),
+ },
+ extensions: ['.js', '.json', '.ts'],
+ },
+ module: {
+ rules: [
+ {
+ test: /\.tsx?$/,
+ use: 'ts-loader',
+ exclude: /node_modules/
+ },
+ {
+ test: /node_modules[\\/]@grpc[\\/]grpc-js/,
+ use: 'null-loader'
+ },
+ {
+ test: /node_modules[\\/]grpc/,
+ use: 'null-loader'
+ },
+ {
+ test: /node_modules[\\/]retry-request/,
+ use: 'null-loader'
+ },
+ {
+ test: /node_modules[\\/]https?-proxy-agent/,
+ use: 'null-loader'
+ },
+ {
+ test: /node_modules[\\/]gtoken/,
+ use: 'null-loader'
+ },
+ ],
+ },
+ mode: 'production',
+};
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/.OwlBot.yaml.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/.OwlBot.yaml.baseline
new file mode 100644
index 000000000000..7feea79e8531
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/.OwlBot.yaml.baseline
@@ -0,0 +1,19 @@
+# Copyright 2025 Google LLC
+#
+# Licensed 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.
+
+deep-copy-regex:
+ - source: /google/samples/resumable/google-samples-resumable-nodejs
+ dest: /owl-bot-staging/google-samples-resumable
+
+api-name: resumable
\ No newline at end of file
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/.gitignore.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/.gitignore.baseline
new file mode 100644
index 000000000000..d4f03a0df2e8
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/.gitignore.baseline
@@ -0,0 +1,14 @@
+**/*.log
+**/node_modules
+/.coverage
+/coverage
+/.nyc_output
+/docs/
+/out/
+/build/
+system-test/secrets.js
+system-test/*key.json
+*.lock
+.DS_Store
+package-lock.json
+__pycache__
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/.jsdoc.js.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/.jsdoc.js.baseline
new file mode 100644
index 000000000000..4b3b51f5549b
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/.jsdoc.js.baseline
@@ -0,0 +1,55 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+'use strict';
+
+module.exports = {
+ opts: {
+ readme: './README.md',
+ package: './package.json',
+ template: './node_modules/jsdoc-fresh',
+ recurse: true,
+ verbose: true,
+ destination: './docs/'
+ },
+ plugins: [
+ 'plugins/markdown',
+ 'jsdoc-region-tag'
+ ],
+ source: {
+ excludePattern: '(^|\\/|\\\\)[._]',
+ include: [
+ 'build/src',
+ 'protos'
+ ],
+ includePattern: '\\.js$'
+ },
+ templates: {
+ copyright: 'Copyright 2026 Google LLC',
+ includeDate: false,
+ sourceFiles: false,
+ systemName: 'resumable',
+ theme: 'lumen',
+ default: {
+ outputSourceFiles: false
+ }
+ },
+ markdown: {
+ idInHeadings: true
+ }
+};
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/.nycrc.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/.nycrc.baseline
new file mode 100644
index 000000000000..81a95fc94b00
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/.nycrc.baseline
@@ -0,0 +1,24 @@
+{
+ "report-dir": "./.coverage",
+ "reporter": ["text", "lcov"],
+ "exclude": [
+ "**/*-test",
+ "**/.coverage",
+ "**/apis",
+ "**/benchmark",
+ "**/conformance",
+ "**/docs",
+ "**/samples",
+ "**/scripts",
+ "**/protos",
+ "**/test",
+ "**/*.d.ts",
+ ".jsdoc.js",
+ "**/.jsdoc.js",
+ "karma.conf.js",
+ "webpack-tests.config.js",
+ "webpack.config.js"
+ ],
+ "exclude-after-remap": false,
+ "all": true
+}
\ No newline at end of file
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/README.md.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/README.md.baseline
new file mode 100644
index 000000000000..582e319d972b
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/README.md.baseline
@@ -0,0 +1,108 @@
+[//]: # "This README.md file is auto-generated, all changes to this file will be lost."
+[//]: # "The comments you see below are used to generate those parts of the template in later states."
+
+
+# [Resumable: Nodejs Client][homepage]
+
+[//]: # "releaseLevel"
+
+[](https://www.npmjs.org/package/resumable)
+
+Resumable client for Node.js
+
+[//]: # "partials.introduction"
+
+A comprehensive list of changes in each version may be found in
+[the CHANGELOG][homepage_changelog].
+
+* [Resumable Nodejs Client API Reference](https://cloud.google.com/nodejs/docs/reference/resumable/latest)
+
+
+Read more about the client libraries for Cloud APIs, including the older
+Google APIs Client Libraries, in [Client Libraries Explained][explained].
+
+[explained]: https://cloud.google.com/apis/docs/client-libraries-explained
+
+**Table of contents:**
+
+* [Quickstart](#quickstart)
+ * [Before you begin](#before-you-begin)
+ * [Installing the client library](#installing-the-client-library)
+
+* [Versioning](#versioning)
+* [Contributing](#contributing)
+* [License](#license)
+
+## Quickstart
+### Before you begin
+
+1. [Select or create a Cloud Platform project][projects].
+1. [Enable billing for your project][billing].
+1. [Enable the Resumable API][enable_api].
+1. [Set up authentication][auth] so you can access the
+ API from your local workstation.
+### Installing the client library
+
+```bash
+npm install resumable
+```
+
+[//]: # "partials.body"
+
+## Samples
+
+Samples are in the [`samples/`][homepage_samples] directory. Each sample's `README.md` has instructions for running its sample.
+
+[//]: # "samples"
+
+## Supported Node.js Versions
+
+Our client libraries follow the [Node.js release schedule](https://github.com/nodejs/release#release-schedule).
+Libraries are compatible with all current _active_ and _maintenance_ versions of
+Node.js.
+If you are using an end-of-life version of Node.js, we recommend that you update
+as soon as possible to an actively supported LTS version.
+
+Google's client libraries support legacy versions of Node.js runtimes on a
+best-efforts basis with the following warnings:
+
+* Legacy versions are not tested in continuous integration.
+* Some security patches and features cannot be backported.
+* Dependencies cannot be kept up-to-date.
+
+Client libraries targeting some end-of-life versions of Node.js are available, and
+can be installed through npm [dist-tags](https://docs.npmjs.com/cli/dist-tag).
+The dist-tags follow the naming convention `legacy-(version)`.
+For example, `npm install resumable@legacy-8` installs client libraries
+for versions compatible with Node.js 8.
+
+## Versioning
+
+This library follows [Semantic Versioning](http://semver.org/).
+
+More Information: [Google Cloud Platform Launch Stages][launch_stages]
+
+[launch_stages]: https://cloud.google.com/terms/launch-stages
+
+## Contributing
+
+Contributions welcome! See the [Contributing Guide](https://github.com/googleapis/google-cloud-node/blob/main/CONTRIBUTING.md).
+
+Please note that this `README.md`
+and a variety of configuration files in this repository (including `.nycrc` and `tsconfig.json`)
+are generated from a central template.
+
+## License
+
+Apache Version 2.0
+
+See [LICENSE](https://github.com/googleapis/google-cloud-node/blob/main/LICENSE)
+
+[shell_img]: https://gstatic.com/cloudssh/images/open-btn.png
+[projects]: https://console.cloud.google.com/project
+[billing]: https://support.google.com/cloud/answer/6293499#enable-billing
+[enable_api]: https://console.cloud.google.com/flows/enableapi?apiid=resumable.googleapis.com
+[auth]: https://cloud.google.com/docs/authentication/external/set-up-adc-local
+[homepage_samples]: https://github.com/googleapis/google-cloud-node/blob/main/packages/google-samples-resumable/samples
+[homepage_changelog]: https://github.com/googleapis/google-cloud-node/blob/main/packages/google-samples-resumable/CHANGELOG.md
+[homepage]: https://github.com/googleapis/google-cloud-node/blob/main/packages/google-samples-resumable
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/package.json b/core/generator/gapic-generator-typescript/baselines/resumable-upload/package.json
new file mode 100644
index 000000000000..564e02d30884
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/package.json
@@ -0,0 +1,64 @@
+{
+ "name": "resumable",
+ "version": "0.1.0",
+ "description": "Resumable client for Node.js",
+ "repository": {
+ "type": "git",
+ "directory": "packages/google-samples-resumable",
+ "url": "https://github.com/googleapis/google-cloud-node.git"
+ },
+ "license": "Apache-2.0",
+ "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-samples-resumable",
+ "author": "Google LLC",
+ "main": "build/src/index.js",
+ "files": [
+ "build/src",
+ "build/protos"
+ ],
+ "keywords": [
+ "google apis client",
+ "google api client",
+ "google apis",
+ "google api",
+ "google",
+ "google cloud platform",
+ "google cloud",
+ "cloud",
+ "google resumable",
+ "resumable",
+ "resumable upload service"
+ ],
+ "scripts": {
+ "clean": "gts clean",
+ "compile": "tsc -p . && cp -r protos build/ && minifyProtoJson",
+ "compile-protos": "compileProtos src",
+ "docs": "jsdoc -c .jsdoc.js",
+ "fix": "gts fix",
+ "lint": "gts check",
+ "prepare": "npm run compile-protos && npm run compile",
+ "system-test": "c8 mocha --config ../../.mocharc.cjs --no-parallel build/system-test",
+ "test": "c8 mocha --config ../../.mocharc.cjs build/test"
+ },
+ "dependencies": {
+ "google-gax": "^6.0.0"
+ },
+ "devDependencies": {
+ "@types/mocha": "^10.0.10",
+ "@types/node": "^22.18.12",
+ "@types/sinon": "^20.0.0",
+ "c8": "^10.1.3",
+ "gapic-tools": "^2.0.0",
+ "gts": "^6.0.2",
+ "jsdoc": "^4.0.5",
+ "jsdoc-fresh": "^6.0.0",
+ "jsdoc-region-tag": "^5.0.0",
+ "long": "^5.3.2",
+ "mocha": "^11.7.4",
+ "pack-n-play": "^5.0.0",
+ "typescript": "5.8.3",
+ "sinon": "^20.0.0"
+ },
+ "engines": {
+ "node": ">=22"
+ }
+}
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/package.json.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/package.json.baseline
new file mode 120000
index 000000000000..2ff8622f1722
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/package.json.baseline
@@ -0,0 +1 @@
+package.json
\ No newline at end of file
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/protos/google/samples/resumable/v1/resumable.proto.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/protos/google/samples/resumable/v1/resumable.proto.baseline
new file mode 100644
index 000000000000..c5980d756f9d
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/protos/google/samples/resumable/v1/resumable.proto.baseline
@@ -0,0 +1,72 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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.
+
+// Synthetic fixture used by the baseline tests to exercise resumable upload
+// method generation via the resumable_upload_methods generator parameter.
+
+syntax = "proto3";
+
+package google.samples.resumable.v1;
+
+import "google/api/annotations.proto";
+import "google/api/client.proto";
+
+option csharp_namespace = "Google.Samples.Resumable.V1";
+option go_package = "google.golang.org/genproto/googleapis/samples/resumable/v1;resumable";
+option java_multiple_files = true;
+option java_outer_classname = "ResumableProto";
+option java_package = "com.google.samples.resumable.v1";
+option php_namespace = "Google\\Samples\\Resumable\\V1";
+option ruby_package = "Google::Samples::Resumable::V1";
+
+service ResumableUploadService {
+ option (google.api.default_host) = "resumable.googleapis.com";
+ option (google.api.oauth_scopes) =
+ "https://www.googleapis.com/auth/cloud-platform";
+
+ // Creates a resumable upload session.
+ rpc CreateResumableUpload(CreateResumableUploadRequest)
+ returns (CreateResumableUploadResponse) {
+ option (google.api.http) = {
+ post: "/v1/uploads"
+ body: "*"
+ };
+ }
+
+ // Returns the status of a previously created upload session.
+ rpc GetUploadStatus(GetUploadStatusRequest)
+ returns (GetUploadStatusResponse) {
+ option (google.api.http) = {
+ get: "/v1/uploads/{upload_url}"
+ };
+ }
+}
+
+message CreateResumableUploadRequest {
+ string name = 1;
+ string description = 2;
+}
+
+message CreateResumableUploadResponse {
+ string upload_url = 1;
+ string status = 2;
+}
+
+message GetUploadStatusRequest {
+ string upload_url = 1;
+}
+
+message GetUploadStatusResponse {
+ string status = 1;
+}
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/samples/generated/v1/resumable_upload_service.create_resumable_upload.js.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/samples/generated/v1/resumable_upload_service.create_resumable_upload.js.baseline
new file mode 100644
index 000000000000..67188e48e219
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/samples/generated/v1/resumable_upload_service.create_resumable_upload.js.baseline
@@ -0,0 +1,65 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+
+
+'use strict';
+
+function main() {
+ // [START resumable_v1_generated_ResumableUploadService_CreateResumableUpload_async]
+ /**
+ * This snippet has been automatically generated and should be regarded as a code template only.
+ * It will require modifications to work.
+ * It may require correct/in-range values for request initialization.
+ * TODO(developer): Uncomment these variables before running the sample.
+ */
+ /**
+ */
+ // const name = 'abc123'
+ /**
+ */
+ // const description = 'abc123'
+
+ // Imports the Resumable library
+ const {ResumableUploadServiceClient} = require('resumable').v1;
+
+ // Instantiates a client
+ const resumableClient = new ResumableUploadServiceClient();
+
+ async function callCreateResumableUpload() {
+ // Construct request
+ const request = {
+ };
+
+ // Run request
+ const session = await resumableClient.createResumableUpload(request);
+ const uploadSource = resumableClient.getResumableSource('/path/to/file');
+ await session.start({uploadSource});
+ const response = await session.finished();
+ console.log(response);
+ }
+
+ callCreateResumableUpload();
+ // [END resumable_v1_generated_ResumableUploadService_CreateResumableUpload_async]
+}
+
+process.on('unhandledRejection', err => {
+ console.error(err.message);
+ process.exitCode = 1;
+});
+main(...process.argv.slice(2));
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/samples/generated/v1/resumable_upload_service.get_upload_status.js.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/samples/generated/v1/resumable_upload_service.get_upload_status.js.baseline
new file mode 100644
index 000000000000..1bc4435b7075
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/samples/generated/v1/resumable_upload_service.get_upload_status.js.baseline
@@ -0,0 +1,59 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+
+
+'use strict';
+
+function main() {
+ // [START resumable_v1_generated_ResumableUploadService_GetUploadStatus_async]
+ /**
+ * This snippet has been automatically generated and should be regarded as a code template only.
+ * It will require modifications to work.
+ * It may require correct/in-range values for request initialization.
+ * TODO(developer): Uncomment these variables before running the sample.
+ */
+ /**
+ */
+ // const uploadUrl = 'abc123'
+
+ // Imports the Resumable library
+ const {ResumableUploadServiceClient} = require('resumable').v1;
+
+ // Instantiates a client
+ const resumableClient = new ResumableUploadServiceClient();
+
+ async function callGetUploadStatus() {
+ // Construct request
+ const request = {
+ };
+
+ // Run request
+ const response = await resumableClient.getUploadStatus(request);
+ console.log(response);
+ }
+
+ callGetUploadStatus();
+ // [END resumable_v1_generated_ResumableUploadService_GetUploadStatus_async]
+}
+
+process.on('unhandledRejection', err => {
+ console.error(err.message);
+ process.exitCode = 1;
+});
+main(...process.argv.slice(2));
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/src/index.ts.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/src/index.ts.baseline
new file mode 100644
index 000000000000..3aac03d6ef20
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/src/index.ts.baseline
@@ -0,0 +1,25 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+import * as v1 from './v1';
+const ResumableUploadServiceClient = v1.ResumableUploadServiceClient;
+type ResumableUploadServiceClient = v1.ResumableUploadServiceClient;
+export {v1, ResumableUploadServiceClient};
+export default {v1, ResumableUploadServiceClient};
+import * as protos from '../protos/protos';
+export {protos};
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/src/v1/index.ts.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/src/v1/index.ts.baseline
new file mode 100644
index 000000000000..10a2b711fd5b
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/src/v1/index.ts.baseline
@@ -0,0 +1,19 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+export {ResumableUploadServiceClient} from './resumable_upload_service_client';
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/src/v1/resumable_upload_service_client.ts.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/src/v1/resumable_upload_service_client.ts.baseline
new file mode 100644
index 000000000000..fe83ada0fc59
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/src/v1/resumable_upload_service_client.ts.baseline
@@ -0,0 +1,601 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+/* global window */
+import type * as gax from 'google-gax';
+import type {
+ Callback,
+ CallOptions,
+ Descriptors,
+ ClientOptions,
+} from 'google-gax';
+
+import * as protos from '../../protos/protos';
+import jsonProtos = require('../../protos/protos.json');
+import {loggingUtils as logging, decodeAnyProtosInArray} from 'google-gax';
+
+/**
+ * Client JSON configuration object, loaded from
+ * `src/v1/resumable_upload_service_client_config.json`.
+ * This file defines retry strategy and timeouts for all API methods in this library.
+ */
+import * as gapicConfig from './resumable_upload_service_client_config.json';
+const version = require('../../../package.json').version;
+
+/**
+ * @class
+ * @memberof v1
+ */
+export class ResumableUploadServiceClient {
+ private _terminated = false;
+ private _opts: ClientOptions;
+ private _providedCustomServicePath: boolean;
+ private _gaxModule: typeof gax | typeof gax.fallback;
+ private _gaxGrpc: gax.GrpcClient | gax.fallback.GrpcClient;
+ private _fallbackRest?: gax.GrpcClient | gax.fallback.GrpcClient;
+ private _protos: {};
+ private _defaults: {[method: string]: gax.CallSettings};
+ private _universeDomain: string;
+ private _servicePath: string;
+ private _log = logging.log('resumable');
+
+ auth: gax.GoogleAuth;
+ descriptors: Descriptors = {
+ page: {},
+ stream: {},
+ longrunning: {},
+ batching: {},
+ resumableUpload: {},
+ };
+ warn: (code: string, message: string, warnType?: string) => void;
+ innerApiCalls: {[name: string]: Function};
+ resumableUploadServiceStub?: Promise<{[name: string]: Function}>;
+
+ /**
+ * Construct an instance of ResumableUploadServiceClient.
+ *
+ * @param {object} [options] - The configuration object.
+ * The options accepted by the constructor are described in detail
+ * in [this document](https://github.com/googleapis/gax-nodejs/blob/main/client-libraries.md#creating-the-client-instance).
+ * The common options are:
+ * @param {object} [options.credentials] - Credentials object.
+ * @param {string} [options.credentials.client_email]
+ * @param {string} [options.credentials.private_key]
+ * @param {string} [options.email] - Account email address. Required when
+ * using a .pem or .p12 keyFilename.
+ * @param {string} [options.keyFilename] - Full path to the a .json, .pem, or
+ * .p12 key downloaded from the Google Developers Console. If you provide
+ * a path to a JSON file, the projectId option below is not necessary.
+ * NOTE: .pem and .p12 require you to specify options.email as well.
+ * @param {number} [options.port] - The port on which to connect to
+ * the remote host.
+ * @param {string} [options.projectId] - The project ID from the Google
+ * Developer's Console, e.g. 'grape-spaceship-123'. We will also check
+ * the environment variable GCLOUD_PROJECT for your project ID. If your
+ * app is running in an environment which supports
+ * {@link https://cloud.google.com/docs/authentication/application-default-credentials Application Default Credentials},
+ * your project ID will be detected automatically.
+ * @param {string} [options.apiEndpoint] - The domain name of the
+ * API remote host.
+ * @param {gax.ClientConfig} [options.clientConfig] - Client configuration override.
+ * Follows the structure of {@link gapicConfig}.
+ * @param {boolean} [options.fallback] - Use HTTP/1.1 REST mode.
+ * For more information, please check the
+ * {@link https://github.com/googleapis/gax-nodejs/blob/main/client-libraries.md#http11-rest-api-mode documentation}.
+ * @param {gax} [gaxInstance]: loaded instance of `google-gax`. Useful if you
+ * need to avoid loading the default gRPC version and want to use the fallback
+ * HTTP implementation. Load only fallback version and pass it to the constructor:
+ * ```
+ * const gax = require('google-gax/build/src/fallback'); // avoids loading google-gax with gRPC
+ * const client = new ResumableUploadServiceClient({fallback: true}, gax);
+ * ```
+ */
+ constructor(
+ opts?: ClientOptions,
+ gaxInstance?: typeof gax | typeof gax.fallback,
+ ) {
+ // Ensure that options include all the required fields.
+ const staticMembers = this
+ .constructor as typeof ResumableUploadServiceClient;
+ if (
+ opts?.universe_domain &&
+ opts?.universeDomain &&
+ opts?.universe_domain !== opts?.universeDomain
+ ) {
+ throw new Error(
+ 'Please set either universe_domain or universeDomain, but not both.',
+ );
+ }
+ const universeDomainEnvVar =
+ typeof process === 'object' && typeof process.env === 'object'
+ ? process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN']
+ : undefined;
+ this._universeDomain =
+ opts?.universeDomain ??
+ opts?.universe_domain ??
+ universeDomainEnvVar ??
+ 'googleapis.com';
+ this._servicePath = 'resumable.' + this._universeDomain;
+ const servicePath =
+ opts?.servicePath || opts?.apiEndpoint || this._servicePath;
+ this._providedCustomServicePath = !!(
+ opts?.servicePath || opts?.apiEndpoint
+ );
+ const port = opts?.port || staticMembers.port;
+ const clientConfig = opts?.clientConfig ?? {};
+ const fallback =
+ opts?.fallback ??
+ (typeof window !== 'undefined' && typeof window?.fetch === 'function');
+ opts = Object.assign({servicePath, port, clientConfig, fallback}, opts);
+
+ // If scopes are unset in options and we're connecting to a non-default endpoint, set scopes just in case.
+ if (servicePath !== this._servicePath && !('scopes' in opts)) {
+ opts['scopes'] = staticMembers.scopes;
+ }
+
+ // Load google-gax module synchronously if needed
+ if (!gaxInstance) {
+ gaxInstance = require('google-gax') as typeof gax;
+ }
+
+ // Choose either gRPC or proto-over-HTTP implementation of google-gax.
+ this._gaxModule = opts.fallback ? gaxInstance.fallback : gaxInstance;
+
+ // Create a `gaxGrpc` object, with any grpc-specific options sent to the client.
+ this._gaxGrpc = new this._gaxModule.GrpcClient(opts);
+
+ // This service contains resumable upload methods, which are HTTPS-only.
+ // Make sure the REST transport is available even when the client was
+ // configured for gRPC.
+ this._fallbackRest = opts.fallback
+ ? this._gaxGrpc
+ : new gaxInstance.fallback.GrpcClient({...opts, fallback: true});
+
+ // Save options to use in initialize() method.
+ this._opts = opts;
+
+ // Save the auth object to the client, for use by other methods.
+ this.auth = this._gaxGrpc.auth as gax.GoogleAuth;
+
+ // Set useJWTAccessWithScope on the auth object.
+ this.auth.useJWTAccessWithScope = true;
+
+ // Set defaultServicePath on the auth object.
+ this.auth.defaultServicePath = this._servicePath;
+
+ // Set the default scopes in auth client if needed.
+ if (servicePath === this._servicePath) {
+ this.auth.defaultScopes = staticMembers.scopes;
+ }
+
+ // Determine the client header string.
+ const clientHeader = [`gax/${this._gaxModule.version}`, `gapic/${version}`];
+ if (typeof process === 'object' && 'versions' in process) {
+ clientHeader.push(`gl-node/${process.versions.node}`);
+ } else {
+ clientHeader.push(`gl-web/${this._gaxModule.version}`);
+ }
+ if (!opts.fallback) {
+ clientHeader.push(`grpc/${this._gaxGrpc.grpcVersion}`);
+ } else {
+ clientHeader.push(`rest/${this._gaxGrpc.grpcVersion}`);
+ }
+ if (opts.libName && opts.libVersion) {
+ clientHeader.push(`${opts.libName}/${opts.libVersion}`);
+ }
+ // Load the applicable protos.
+ this._protos = this._gaxGrpc.loadProtoJSON(jsonProtos);
+
+ // Some methods on this API support resumable uploads; provide
+ // descriptors for these methods.
+ this.descriptors.resumableUpload = {
+ createResumableUpload: new this._gaxModule.ResumableUploadDescriptor(
+ '/resumable/upload',
+ ),
+ };
+
+ // Put together the default options sent with requests.
+ this._defaults = this._gaxGrpc.constructSettings(
+ 'google.samples.resumable.v1.ResumableUploadService',
+ gapicConfig as gax.ClientConfig,
+ opts.clientConfig || {},
+ {'x-goog-api-client': clientHeader.join(' ')},
+ );
+
+ // Set up a dictionary of "inner API calls"; the core implementation
+ // of calling the API is handled in `google-gax`, with this code
+ // merely providing the destination and request information.
+ this.innerApiCalls = {};
+
+ // Add a warn function to the client constructor so it can be easily tested.
+ this.warn = this._gaxModule.warn;
+ }
+
+ /**
+ * Initialize the client.
+ * Performs asynchronous operations (such as authentication) and prepares the client.
+ * This function will be called automatically when any class method is called for the
+ * first time, but if you need to initialize it before calling an actual method,
+ * feel free to call initialize() directly.
+ *
+ * You can await on this method if you want to make sure the client is initialized.
+ *
+ * @returns {Promise} A promise that resolves to an authenticated service stub.
+ */
+ initialize() {
+ // If the client stub promise is already initialized, return immediately.
+ if (this.resumableUploadServiceStub) {
+ return this.resumableUploadServiceStub;
+ }
+
+ // Put together the "service stub" for
+ // google.samples.resumable.v1.ResumableUploadService.
+ this.resumableUploadServiceStub = this._gaxGrpc.createStub(
+ this._opts.fallback
+ ? (this._protos as protobuf.Root).lookupService(
+ 'google.samples.resumable.v1.ResumableUploadService',
+ )
+ : // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (this._protos as any).google.samples.resumable.v1
+ .ResumableUploadService,
+ this._opts,
+ this._providedCustomServicePath,
+ ) as Promise<{[method: string]: Function}>;
+
+ // Iterate over each of the methods that the service provides
+ // and create an API call method for each.
+ const resumableUploadServiceStubMethods = ['getUploadStatus'];
+ for (const methodName of resumableUploadServiceStubMethods) {
+ const callPromise = this.resumableUploadServiceStub.then(
+ stub =>
+ (...args: Array<{}>) => {
+ if (this._terminated) {
+ return Promise.reject('The client has already been closed.');
+ }
+ const func = stub[methodName];
+ return func.apply(stub, args);
+ },
+ (err: Error | null | undefined) => () => {
+ throw err;
+ },
+ );
+
+ const descriptor = undefined;
+ const apiCall = this._gaxModule.createApiCall(
+ callPromise,
+ this._defaults[methodName],
+ descriptor,
+ this._opts.fallback,
+ );
+
+ this.innerApiCalls[methodName] = apiCall;
+ }
+
+ // Resumable upload methods do not use the gRPC/REST service stub; the
+ // The ResumableUploadSession performs its own HTTP requests.
+ this.innerApiCalls['createResumableUpload'] = this._gaxModule.createApiCall(
+ this._gaxModule.resumableUploadStub,
+ this._defaults['createResumableUpload'],
+ this.descriptors.resumableUpload!['createResumableUpload'],
+ this._opts.fallback,
+ );
+
+ return this.resumableUploadServiceStub;
+ }
+
+ /**
+ * The DNS address for this API service.
+ * @deprecated Use the apiEndpoint method of the client instance.
+ * @returns {string} The DNS address for this service.
+ */
+ static get servicePath() {
+ if (
+ typeof process === 'object' &&
+ typeof process.emitWarning === 'function'
+ ) {
+ process.emitWarning(
+ 'Static servicePath is deprecated, please use the instance method instead.',
+ 'DeprecationWarning',
+ );
+ }
+ return 'resumable.googleapis.com';
+ }
+
+ /**
+ * The DNS address for this API service - same as servicePath.
+ * @deprecated Use the apiEndpoint method of the client instance.
+ * @returns {string} The DNS address for this service.
+ */
+ static get apiEndpoint() {
+ if (
+ typeof process === 'object' &&
+ typeof process.emitWarning === 'function'
+ ) {
+ process.emitWarning(
+ 'Static apiEndpoint is deprecated, please use the instance method instead.',
+ 'DeprecationWarning',
+ );
+ }
+ return 'resumable.googleapis.com';
+ }
+
+ /**
+ * The DNS address for this API service.
+ * @returns {string} The DNS address for this service.
+ */
+ get apiEndpoint() {
+ return this._servicePath;
+ }
+
+ get universeDomain() {
+ return this._universeDomain;
+ }
+
+ /**
+ * The port for this API service.
+ * @returns {number} The default port for this service.
+ */
+ static get port() {
+ return 443;
+ }
+
+ /**
+ * The scopes needed to make gRPC calls for every method defined
+ * in this service.
+ * @returns {string[]} List of default scopes.
+ */
+ static get scopes() {
+ return ['https://www.googleapis.com/auth/cloud-platform'];
+ }
+
+ getProjectId(): Promise;
+ getProjectId(callback: Callback): void;
+ /**
+ * Return the project ID used by this class.
+ * @returns {Promise} A promise that resolves to string containing the project ID.
+ */
+ getProjectId(
+ callback?: Callback,
+ ): Promise | void {
+ if (callback) {
+ this.auth.getProjectId(callback);
+ return;
+ }
+ return this.auth.getProjectId();
+ }
+
+ // -------------------
+ // -- Service calls --
+ // -------------------
+ /**
+ * Returns the status of a previously created upload session.
+ *
+ * @param {Object} request
+ * The request object that will be sent.
+ * @param {string} request.uploadUrl
+ * @param {object} [options]
+ * Call options. See {@link https://googleapis.dev/nodejs/google-gax/latest/interfaces/CallOptions.html|CallOptions} for more details.
+ * @returns {Promise} - The promise which resolves to an array.
+ * The first element of the array is an object representing {@link protos.google.samples.resumable.v1.GetUploadStatusResponse|GetUploadStatusResponse}.
+ * Please see the {@link https://github.com/googleapis/gax-nodejs/blob/master/client-libraries.md#regular-methods | documentation }
+ * for more details and examples.
+ * @example include:samples/generated/v1/resumable_upload_service.get_upload_status.js
+ * region_tag:resumable_v1_generated_ResumableUploadService_GetUploadStatus_async
+ */
+ getUploadStatus(
+ request?: protos.google.samples.resumable.v1.IGetUploadStatusRequest,
+ options?: CallOptions,
+ ): Promise<
+ [
+ protos.google.samples.resumable.v1.IGetUploadStatusResponse,
+ protos.google.samples.resumable.v1.IGetUploadStatusRequest | undefined,
+ {} | undefined,
+ ]
+ >;
+ getUploadStatus(
+ request: protos.google.samples.resumable.v1.IGetUploadStatusRequest,
+ options: CallOptions,
+ callback: Callback<
+ protos.google.samples.resumable.v1.IGetUploadStatusResponse,
+ | protos.google.samples.resumable.v1.IGetUploadStatusRequest
+ | null
+ | undefined,
+ {} | null | undefined
+ >,
+ ): void;
+ getUploadStatus(
+ request: protos.google.samples.resumable.v1.IGetUploadStatusRequest,
+ callback: Callback<
+ protos.google.samples.resumable.v1.IGetUploadStatusResponse,
+ | protos.google.samples.resumable.v1.IGetUploadStatusRequest
+ | null
+ | undefined,
+ {} | null | undefined
+ >,
+ ): void;
+ getUploadStatus(
+ request?: protos.google.samples.resumable.v1.IGetUploadStatusRequest,
+ optionsOrCallback?:
+ | CallOptions
+ | Callback<
+ protos.google.samples.resumable.v1.IGetUploadStatusResponse,
+ | protos.google.samples.resumable.v1.IGetUploadStatusRequest
+ | null
+ | undefined,
+ {} | null | undefined
+ >,
+ callback?: Callback<
+ protos.google.samples.resumable.v1.IGetUploadStatusResponse,
+ | protos.google.samples.resumable.v1.IGetUploadStatusRequest
+ | null
+ | undefined,
+ {} | null | undefined
+ >,
+ ): Promise<
+ [
+ protos.google.samples.resumable.v1.IGetUploadStatusResponse,
+ protos.google.samples.resumable.v1.IGetUploadStatusRequest | undefined,
+ {} | undefined,
+ ]
+ > | void {
+ request = request || {};
+ let options: CallOptions;
+ if (typeof optionsOrCallback === 'function' && callback === undefined) {
+ callback = optionsOrCallback;
+ options = {};
+ } else {
+ options = optionsOrCallback as CallOptions;
+ }
+ options = options || {};
+ options.otherArgs = options.otherArgs || {};
+ options.otherArgs.headers = options.otherArgs.headers || {};
+ options.otherArgs.headers['x-goog-request-params'] =
+ this._gaxModule.routingHeader.fromParams({
+ upload_url: request.uploadUrl ?? '',
+ });
+ this.initialize().catch(err => {
+ throw err;
+ });
+ this._log.info('getUploadStatus request %j', request);
+ const wrappedCallback:
+ | Callback<
+ protos.google.samples.resumable.v1.IGetUploadStatusResponse,
+ | protos.google.samples.resumable.v1.IGetUploadStatusRequest
+ | null
+ | undefined,
+ {} | null | undefined
+ >
+ | undefined = callback
+ ? (error, response, options, rawResponse) => {
+ this._log.info('getUploadStatus response %j', response);
+ callback!(error, response, options, rawResponse); // We verified callback above.
+ }
+ : undefined;
+ return this.innerApiCalls
+ .getUploadStatus(request, options, wrappedCallback)
+ ?.then(
+ ([response, options, rawResponse]: [
+ protos.google.samples.resumable.v1.IGetUploadStatusResponse,
+ (
+ | protos.google.samples.resumable.v1.IGetUploadStatusRequest
+ | undefined
+ ),
+ {} | undefined,
+ ]) => {
+ this._log.info('getUploadStatus response %j', response);
+ return [response, options, rawResponse];
+ },
+ )
+ .catch((error: any) => {
+ if (
+ error &&
+ 'statusDetails' in error &&
+ error.statusDetails instanceof Array
+ ) {
+ const protos = this._gaxModule.protobuf.Root.fromJSON(
+ jsonProtos,
+ ) as unknown as gax.protobuf.Type;
+ error.statusDetails = decodeAnyProtosInArray(
+ error.statusDetails,
+ protos,
+ );
+ }
+ throw error;
+ });
+ }
+ /**
+ * Creates a {@link gax.ResumableSource} backed by a local file.
+ *
+ * This delegates to google-gax so generated clients do not depend on the
+ * Node.js `fs` module at import time. The source can be passed as the
+ * `uploadSource` parameter of {@link gax.ResumableUploadSession#start}.
+ *
+ * @param {string} filePath - Path to the local file to upload.
+ * @returns {gax.ResumableSource} A seekable upload source for the file.
+ */
+ getResumableSource(filePath: string): gax.ResumableSource {
+ const gaxModule = this._gaxModule as typeof gax;
+ return gaxModule.resumableSourceFromFile(filePath);
+ }
+ /**
+ * Creates a resumable upload session.
+ *
+ * @param {object} [request] - The request object.
+ * @param {object} [options] - Optional parameters. The upload source, chunk
+ * size, progress callback, and resume URL are passed to
+ * {@link gax.ResumableUploadSession#start} instead.
+ * @returns {Promise} A resumable upload session.
+ * Call `.start(uploadParams)` with the source to upload, then await
+ * `.finished()` for the final RPC response.
+ */
+ createResumableUpload(
+ request?: protos.google.samples.resumable.v1.ICreateResumableUploadRequest,
+ options?: CallOptions,
+ ): Promise {
+ request = request || {};
+ options = options || {};
+ if (!this._opts.fallback && this._opts.sslCreds) {
+ return Promise.reject(
+ new this._gaxModule.GoogleError(
+ 'Resumable upload methods require HTTP(S) authentication and ' +
+ 'cannot be used with gRPC channel credentials. Configure the ' +
+ 'client without `sslCreds`, or use `fallback: true`.',
+ ),
+ );
+ }
+ this.initialize().catch(err => {
+ throw err;
+ });
+ this._log.info('createResumableUpload request %j', request);
+ return (
+ this.innerApiCalls['createResumableUpload'](request, {
+ ...options,
+ resumableUpload: {
+ auth: this._fallbackRest!.auth as gax.GoogleAuth,
+ servicePath: this._opts.servicePath ?? this._servicePath,
+ servicePort: this._opts.port || 443,
+ protocol: this._opts.protocol || 'https',
+ rpc: this._gaxModule.protobuf.Root.fromJSON(jsonProtos).lookupService(
+ 'google.samples.resumable.v1.ResumableUploadService',
+ ).methods['CreateResumableUpload'],
+ request,
+ uploadPrefix: '/resumable/upload',
+ numericEnums: this._opts.numericEnums,
+ minifyJson: this._opts.minifyJson,
+ },
+ }) as Promise<[gax.ResumableUploadSession]>
+ ).then(([session]) => session);
+ }
+
+ /**
+ * Terminate the gRPC channel and close the client.
+ *
+ * The client will no longer be usable and all future behavior is undefined.
+ * @returns {Promise} A promise that resolves when the client is closed.
+ */
+ close(): Promise {
+ if (this.resumableUploadServiceStub && !this._terminated) {
+ return this.resumableUploadServiceStub.then(stub => {
+ this._log.info('ending gRPC channel');
+ this._terminated = true;
+ stub.close();
+ });
+ }
+ return Promise.resolve();
+ }
+}
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/src/v1/resumable_upload_service_client_config.json.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/src/v1/resumable_upload_service_client_config.json.baseline
new file mode 100644
index 000000000000..de3f9fed6441
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/src/v1/resumable_upload_service_client_config.json.baseline
@@ -0,0 +1,34 @@
+{
+ "interfaces": {
+ "google.samples.resumable.v1.ResumableUploadService": {
+ "retry_codes": {
+ "non_idempotent": [],
+ "idempotent": [
+ "DEADLINE_EXCEEDED",
+ "UNAVAILABLE"
+ ]
+ },
+ "retry_params": {
+ "default": {
+ "initial_retry_delay_millis": 100,
+ "retry_delay_multiplier": 1.3,
+ "max_retry_delay_millis": 60000,
+ "initial_rpc_timeout_millis": 60000,
+ "rpc_timeout_multiplier": 1,
+ "max_rpc_timeout_millis": 60000,
+ "total_timeout_millis": 600000
+ }
+ },
+ "methods": {
+ "CreateResumableUpload": {
+ "retry_codes_name": "non_idempotent",
+ "retry_params_name": "default"
+ },
+ "GetUploadStatus": {
+ "retry_codes_name": "non_idempotent",
+ "retry_params_name": "default"
+ }
+ }
+ }
+ }
+}
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/src/v1/resumable_upload_service_proto_list.json.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/src/v1/resumable_upload_service_proto_list.json.baseline
new file mode 100644
index 000000000000..4acc3ac38ace
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/src/v1/resumable_upload_service_proto_list.json.baseline
@@ -0,0 +1,3 @@
+[
+ "../../protos/google/samples/resumable/v1/resumable.proto"
+]
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/system-test/fixtures/sample/src/index.js.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/system-test/fixtures/sample/src/index.js.baseline
new file mode 100644
index 000000000000..49a3b15d7ff1
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/system-test/fixtures/sample/src/index.js.baseline
@@ -0,0 +1,27 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+
+/* eslint-disable node/no-missing-require, no-unused-vars */
+const resumable = require('resumable');
+
+function main() {
+ const resumableUploadServiceClient = new resumable.ResumableUploadServiceClient();
+}
+
+main();
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/system-test/fixtures/sample/src/index.ts.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/system-test/fixtures/sample/src/index.ts.baseline
new file mode 100644
index 000000000000..3c57d32a6bb3
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/system-test/fixtures/sample/src/index.ts.baseline
@@ -0,0 +1,34 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+import {ResumableUploadServiceClient} from 'resumable';
+
+// check that the client class type name can be used
+function doStuffWithResumableUploadServiceClient(
+ client: ResumableUploadServiceClient,
+) {
+ client.close();
+}
+
+function main() {
+ // check that the client instance can be created
+ const resumableUploadServiceClient = new ResumableUploadServiceClient();
+ doStuffWithResumableUploadServiceClient(resumableUploadServiceClient);
+}
+
+main();
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/system-test/install.ts.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/system-test/install.ts.baseline
new file mode 100644
index 000000000000..79d5bea3c93e
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/system-test/install.ts.baseline
@@ -0,0 +1,51 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+import {packNTest} from 'pack-n-play';
+import {readFileSync} from 'fs';
+import {describe, it} from 'mocha';
+
+describe('📦 pack-n-play test', () => {
+ it('TypeScript code', async function () {
+ this.timeout(300000);
+ const options = {
+ packageDir: process.cwd(),
+ sample: {
+ description: 'TypeScript user can use the type definitions',
+ ts: readFileSync(
+ './system-test/fixtures/sample/src/index.ts',
+ ).toString(),
+ },
+ };
+ await packNTest(options);
+ });
+
+ it('JavaScript code', async function () {
+ this.timeout(300000);
+ const options = {
+ packageDir: process.cwd(),
+ sample: {
+ description: 'JavaScript user can use the library',
+ cjs: readFileSync(
+ './system-test/fixtures/sample/src/index.js',
+ ).toString(),
+ },
+ };
+ await packNTest(options);
+ });
+});
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/test/gapic_resumable_upload_service_v1.ts.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/test/gapic_resumable_upload_service_v1.ts.baseline
new file mode 100644
index 000000000000..f8fa88cfa884
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/test/gapic_resumable_upload_service_v1.ts.baseline
@@ -0,0 +1,408 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+//
+// ** This file is automatically generated by gapic-generator-typescript. **
+// ** https://github.com/googleapis/gapic-generator-typescript **
+// ** All changes to this file may be overwritten. **
+
+import * as protos from '../protos/protos';
+import * as assert from 'assert';
+import * as sinon from 'sinon';
+import {SinonStub} from 'sinon';
+import {describe, it} from 'mocha';
+import * as resumableuploadserviceModule from '../src';
+
+import {protobuf} from 'google-gax';
+
+// Dynamically loaded proto JSON is needed to get the type information
+// to fill in default values for request objects
+const root = protobuf.Root.fromJSON(
+ require('../protos/protos.json'),
+).resolveAll();
+
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+function getTypeDefaultValue(typeName: string, fields: string[]) {
+ let type = root.lookupType(typeName) as protobuf.Type;
+ for (const field of fields.slice(0, -1)) {
+ type = type.fields[field]?.resolvedType as protobuf.Type;
+ }
+ return type.fields[fields[fields.length - 1]]?.defaultValue;
+}
+
+function generateSampleMessage(instance: T) {
+ const filledObject = (
+ instance.constructor as typeof protobuf.Message
+ ).toObject(instance as protobuf.Message, {defaults: true});
+ return (instance.constructor as typeof protobuf.Message).fromObject(
+ filledObject,
+ ) as T;
+}
+
+function stubSimpleCall(response?: ResponseType, error?: Error) {
+ return error
+ ? sinon.stub().rejects(error)
+ : sinon.stub().resolves([response]);
+}
+
+function stubSimpleCallWithCallback(
+ response?: ResponseType,
+ error?: Error,
+) {
+ return error
+ ? sinon.stub().callsArgWith(2, error)
+ : sinon.stub().callsArgWith(2, null, response);
+}
+
+describe('v1.ResumableUploadServiceClient', () => {
+ describe('Common methods', () => {
+ it('has apiEndpoint', () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient();
+ const apiEndpoint = client.apiEndpoint;
+ assert.strictEqual(apiEndpoint, 'resumable.googleapis.com');
+ });
+
+ it('has universeDomain', () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient();
+ const universeDomain = client.universeDomain;
+ assert.strictEqual(universeDomain, 'googleapis.com');
+ });
+
+ if (
+ typeof process === 'object' &&
+ typeof process.emitWarning === 'function'
+ ) {
+ it('throws DeprecationWarning if static servicePath is used', () => {
+ const stub = sinon.stub(process, 'emitWarning');
+ const servicePath =
+ resumableuploadserviceModule.v1.ResumableUploadServiceClient
+ .servicePath;
+ assert.strictEqual(servicePath, 'resumable.googleapis.com');
+ assert(stub.called);
+ stub.restore();
+ });
+
+ it('throws DeprecationWarning if static apiEndpoint is used', () => {
+ const stub = sinon.stub(process, 'emitWarning');
+ const apiEndpoint =
+ resumableuploadserviceModule.v1.ResumableUploadServiceClient
+ .apiEndpoint;
+ assert.strictEqual(apiEndpoint, 'resumable.googleapis.com');
+ assert(stub.called);
+ stub.restore();
+ });
+ }
+ it('sets apiEndpoint according to universe domain camelCase', () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ universeDomain: 'example.com',
+ });
+ const servicePath = client.apiEndpoint;
+ assert.strictEqual(servicePath, 'resumable.example.com');
+ });
+
+ it('sets apiEndpoint according to universe domain snakeCase', () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ universe_domain: 'example.com',
+ });
+ const servicePath = client.apiEndpoint;
+ assert.strictEqual(servicePath, 'resumable.example.com');
+ });
+
+ if (typeof process === 'object' && 'env' in process) {
+ describe('GOOGLE_CLOUD_UNIVERSE_DOMAIN environment variable', () => {
+ it('sets apiEndpoint from environment variable', () => {
+ const saved = process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'];
+ process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'] = 'example.com';
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient();
+ const servicePath = client.apiEndpoint;
+ assert.strictEqual(servicePath, 'resumable.example.com');
+ if (saved) {
+ process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'] = saved;
+ } else {
+ delete process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'];
+ }
+ });
+
+ it('value configured in code has priority over environment variable', () => {
+ const saved = process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'];
+ process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'] = 'example.com';
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ universeDomain: 'configured.example.com',
+ });
+ const servicePath = client.apiEndpoint;
+ assert.strictEqual(servicePath, 'resumable.configured.example.com');
+ if (saved) {
+ process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'] = saved;
+ } else {
+ delete process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'];
+ }
+ });
+ });
+ }
+ it('does not allow setting both universeDomain and universe_domain', () => {
+ assert.throws(() => {
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ universe_domain: 'example.com',
+ universeDomain: 'example.net',
+ });
+ });
+ });
+
+ it('has port', () => {
+ const port =
+ resumableuploadserviceModule.v1.ResumableUploadServiceClient.port;
+ assert(port);
+ assert(typeof port === 'number');
+ });
+
+ it('should create a client with no option', () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient();
+ assert(client);
+ });
+
+ it('should create a client with gRPC fallback', () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ fallback: true,
+ });
+ assert(client);
+ });
+
+ it('has initialize method and supports deferred initialization', async () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ assert.strictEqual(client.resumableUploadServiceStub, undefined);
+ await client.initialize();
+ assert(client.resumableUploadServiceStub);
+ });
+
+ it('has close method for the initialized client', done => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ client.initialize().catch(err => {
+ throw err;
+ });
+ assert(client.resumableUploadServiceStub);
+ client
+ .close()
+ .then(() => {
+ done();
+ })
+ .catch(err => {
+ throw err;
+ });
+ });
+
+ it('has close method for the non-initialized client', done => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ assert.strictEqual(client.resumableUploadServiceStub, undefined);
+ client
+ .close()
+ .then(() => {
+ done();
+ })
+ .catch(err => {
+ throw err;
+ });
+ });
+
+ it('has getProjectId method', async () => {
+ const fakeProjectId = 'fake-project-id';
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ client.auth.getProjectId = sinon.stub().resolves(fakeProjectId);
+ const result = await client.getProjectId();
+ assert.strictEqual(result, fakeProjectId);
+ assert((client.auth.getProjectId as SinonStub).calledWithExactly());
+ });
+
+ it('has getProjectId method with callback', async () => {
+ const fakeProjectId = 'fake-project-id';
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ client.auth.getProjectId = sinon
+ .stub()
+ .callsArgWith(0, null, fakeProjectId);
+ const promise = new Promise((resolve, reject) => {
+ client.getProjectId((err?: Error | null, projectId?: string | null) => {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(projectId);
+ }
+ });
+ });
+ const result = await promise;
+ assert.strictEqual(result, fakeProjectId);
+ });
+ });
+
+ describe('getUploadStatus', () => {
+ it('invokes getUploadStatus without error', async () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ await client.initialize();
+ const request = generateSampleMessage(
+ new protos.google.samples.resumable.v1.GetUploadStatusRequest(),
+ );
+ const defaultValue1 = getTypeDefaultValue(
+ '.google.samples.resumable.v1.GetUploadStatusRequest',
+ ['uploadUrl'],
+ );
+ request.uploadUrl = defaultValue1;
+ const expectedHeaderRequestParams = `upload_url=${defaultValue1 ?? ''}`;
+ const expectedResponse = generateSampleMessage(
+ new protos.google.samples.resumable.v1.GetUploadStatusResponse(),
+ );
+ client.innerApiCalls.getUploadStatus = stubSimpleCall(expectedResponse);
+ const [response] = await client.getUploadStatus(request);
+ assert.deepStrictEqual(response, expectedResponse);
+ const actualRequest = (
+ client.innerApiCalls.getUploadStatus as SinonStub
+ ).getCall(0).args[0];
+ assert.deepStrictEqual(actualRequest, request);
+ const actualHeaderRequestParams = (
+ client.innerApiCalls.getUploadStatus as SinonStub
+ ).getCall(0).args[1].otherArgs.headers['x-goog-request-params'];
+ assert(actualHeaderRequestParams.includes(expectedHeaderRequestParams));
+ });
+
+ it('invokes getUploadStatus without error using callback', async () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ await client.initialize();
+ const request = generateSampleMessage(
+ new protos.google.samples.resumable.v1.GetUploadStatusRequest(),
+ );
+ const defaultValue1 = getTypeDefaultValue(
+ '.google.samples.resumable.v1.GetUploadStatusRequest',
+ ['uploadUrl'],
+ );
+ request.uploadUrl = defaultValue1;
+ const expectedHeaderRequestParams = `upload_url=${defaultValue1 ?? ''}`;
+ const expectedResponse = generateSampleMessage(
+ new protos.google.samples.resumable.v1.GetUploadStatusResponse(),
+ );
+ client.innerApiCalls.getUploadStatus =
+ stubSimpleCallWithCallback(expectedResponse);
+ const promise = new Promise((resolve, reject) => {
+ client.getUploadStatus(
+ request,
+ (
+ err?: Error | null,
+ result?: protos.google.samples.resumable.v1.IGetUploadStatusResponse | null,
+ ) => {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(result);
+ }
+ },
+ );
+ });
+ const response = await promise;
+ assert.deepStrictEqual(response, expectedResponse);
+ const actualRequest = (
+ client.innerApiCalls.getUploadStatus as SinonStub
+ ).getCall(0).args[0];
+ assert.deepStrictEqual(actualRequest, request);
+ const actualHeaderRequestParams = (
+ client.innerApiCalls.getUploadStatus as SinonStub
+ ).getCall(0).args[1].otherArgs.headers['x-goog-request-params'];
+ assert(actualHeaderRequestParams.includes(expectedHeaderRequestParams));
+ });
+
+ it('invokes getUploadStatus with error', async () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ await client.initialize();
+ const request = generateSampleMessage(
+ new protos.google.samples.resumable.v1.GetUploadStatusRequest(),
+ );
+ const defaultValue1 = getTypeDefaultValue(
+ '.google.samples.resumable.v1.GetUploadStatusRequest',
+ ['uploadUrl'],
+ );
+ request.uploadUrl = defaultValue1;
+ const expectedHeaderRequestParams = `upload_url=${defaultValue1 ?? ''}`;
+ const expectedError = new Error('expected');
+ client.innerApiCalls.getUploadStatus = stubSimpleCall(
+ undefined,
+ expectedError,
+ );
+ await assert.rejects(client.getUploadStatus(request), expectedError);
+ const actualRequest = (
+ client.innerApiCalls.getUploadStatus as SinonStub
+ ).getCall(0).args[0];
+ assert.deepStrictEqual(actualRequest, request);
+ const actualHeaderRequestParams = (
+ client.innerApiCalls.getUploadStatus as SinonStub
+ ).getCall(0).args[1].otherArgs.headers['x-goog-request-params'];
+ assert(actualHeaderRequestParams.includes(expectedHeaderRequestParams));
+ });
+
+ it('invokes getUploadStatus with closed client', async () => {
+ const client =
+ new resumableuploadserviceModule.v1.ResumableUploadServiceClient({
+ credentials: {client_email: 'bogus', private_key: 'bogus'},
+ projectId: 'bogus',
+ });
+ await client.initialize();
+ const request = generateSampleMessage(
+ new protos.google.samples.resumable.v1.GetUploadStatusRequest(),
+ );
+ const defaultValue1 = getTypeDefaultValue(
+ '.google.samples.resumable.v1.GetUploadStatusRequest',
+ ['uploadUrl'],
+ );
+ request.uploadUrl = defaultValue1;
+ const expectedError = new Error('The client has already been closed.');
+ client.close().catch(err => {
+ throw err;
+ });
+ await assert.rejects(client.getUploadStatus(request), expectedError);
+ });
+ });
+});
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/tsconfig.json.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/tsconfig.json.baseline
new file mode 100644
index 000000000000..ca73e7bfc824
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/tsconfig.json.baseline
@@ -0,0 +1,22 @@
+{
+ "extends": "./node_modules/gts/tsconfig-google.json",
+ "compilerOptions": {
+ "rootDir": ".",
+ "outDir": "build",
+ "resolveJsonModule": true,
+ "lib": [
+ "es2023",
+ "dom"
+ ]
+ },
+ "include": [
+ "src/*.ts",
+ "src/**/*.ts",
+ "test/*.ts",
+ "test/**/*.ts",
+ "system-test/*.ts",
+ "src/**/*.json",
+ "samples/**/*.json",
+ "protos/protos.json"
+ ]
+}
diff --git a/core/generator/gapic-generator-typescript/baselines/resumable-upload/webpack.config.js.baseline b/core/generator/gapic-generator-typescript/baselines/resumable-upload/webpack.config.js.baseline
new file mode 100644
index 000000000000..0a553e060843
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/baselines/resumable-upload/webpack.config.js.baseline
@@ -0,0 +1,64 @@
+// Copyright 2021 Google LLC
+//
+// Licensed 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
+//
+// https://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.
+
+const path = require('path');
+
+module.exports = {
+ entry: './src/index.ts',
+ output: {
+ library: 'ResumableUploadService',
+ filename: './resumable-upload-service.js',
+ },
+ node: {
+ child_process: 'empty',
+ fs: 'empty',
+ crypto: 'empty',
+ },
+ resolve: {
+ alias: {
+ '../../../package.json': path.resolve(__dirname, 'package.json'),
+ },
+ extensions: ['.js', '.json', '.ts'],
+ },
+ module: {
+ rules: [
+ {
+ test: /\.tsx?$/,
+ use: 'ts-loader',
+ exclude: /node_modules/
+ },
+ {
+ test: /node_modules[\\/]@grpc[\\/]grpc-js/,
+ use: 'null-loader'
+ },
+ {
+ test: /node_modules[\\/]grpc/,
+ use: 'null-loader'
+ },
+ {
+ test: /node_modules[\\/]retry-request/,
+ use: 'null-loader'
+ },
+ {
+ test: /node_modules[\\/]https?-proxy-agent/,
+ use: 'null-loader'
+ },
+ {
+ test: /node_modules[\\/]gtoken/,
+ use: 'null-loader'
+ },
+ ],
+ },
+ mode: 'production',
+};
diff --git a/core/generator/gapic-generator-typescript/rules_typescript_gapic/typescript_gapic.bzl b/core/generator/gapic-generator-typescript/rules_typescript_gapic/typescript_gapic.bzl
index b76a85508c26..0385513a47a3 100644
--- a/core/generator/gapic-generator-typescript/rules_typescript_gapic/typescript_gapic.bzl
+++ b/core/generator/gapic-generator-typescript/rules_typescript_gapic/typescript_gapic.bzl
@@ -30,6 +30,7 @@ def typescript_gapic_library(
legacy_proto_load = None,
rest_numeric_enums = None,
mixins = None,
+ resumable_upload_methods = None,
format = None,
extra_protoc_parameters = [],
extra_protoc_file_parameters = {},
@@ -56,6 +57,8 @@ def typescript_gapic_library(
plugin_args_dict["rest-numeric-enums"] = "true"
if mixins:
plugin_args_dict["mixins"] = mixins
+ if resumable_upload_methods:
+ plugin_args_dict["resumable-upload-methods"] = resumable_upload_methods
file_args = {} # note: keys are filenames, values are parameter name, aligned with the prior art
for key, value in extra_protoc_file_parameters:
diff --git a/core/generator/gapic-generator-typescript/templates/cjs/typescript_gapic/src/$version/$service_client.ts.njk b/core/generator/gapic-generator-typescript/templates/cjs/typescript_gapic/src/$version/$service_client.ts.njk
index 82dded752187..21eb410b98a9 100644
--- a/core/generator/gapic-generator-typescript/templates/cjs/typescript_gapic/src/$version/$service_client.ts.njk
+++ b/core/generator/gapic-generator-typescript/templates/cjs/typescript_gapic/src/$version/$service_client.ts.njk
@@ -78,6 +78,9 @@ export class {{ service.name }}Client {
private _providedCustomServicePath: boolean;
private _gaxModule: typeof gax{% if not api.legacyProtoLoad %} | typeof gax.fallback{% endif %};
private _gaxGrpc: gax.GrpcClient{% if not api.legacyProtoLoad %} | gax.fallback.GrpcClient{% endif %};
+{%- if not api.legacyProtoLoad and service.resumableUploads.length > 0 %}
+ private _fallbackRest?: gax.GrpcClient | gax.fallback.GrpcClient;
+{%- endif %}
private _protos: {};
private _defaults: {[method: string]: gax.CallSettings};
private _universeDomain: string;
@@ -90,6 +93,9 @@ export class {{ service.name }}Client {
stream: {},
longrunning: {},
batching: {},
+{%- if not api.legacyProtoLoad and service.resumableUploads.length > 0 %}
+ resumableUpload: {},
+{%- endif %}
};
warn: (code: string, message: string, warnType?: string) => void;
innerApiCalls: {[name: string]: Function};
@@ -202,6 +208,15 @@ export class {{ service.name }}Client {
// Create a `gaxGrpc` object, with any grpc-specific options sent to the client.
this._gaxGrpc = new this._gaxModule.GrpcClient(opts);
+{%- if not api.legacyProtoLoad and service.resumableUploads.length > 0 %}
+
+ // This service contains resumable upload methods, which are HTTPS-only.
+ // Make sure the REST transport is available even when the client was
+ // configured for gRPC.
+ this._fallbackRest = opts.fallback
+ ? this._gaxGrpc
+ : new gaxInstance.fallback.GrpcClient({...opts, fallback: true});
+{%- endif %}
// Save options to use in {{ id.get("initialize") }}() method.
this._opts = opts;
@@ -399,6 +414,21 @@ export class {{ service.name }}Client {
};
{%- endif %}
+{%- if not api.legacyProtoLoad and service.resumableUploads.length > 0 %}
+
+ // Some methods on this API support resumable uploads; provide
+ // descriptors for these methods.
+ this.descriptors.resumableUpload = {
+{%- set resumableUploadJoiner = joiner() %}
+{%- for method in service.resumableUploads %}
+ {{- resumableUploadJoiner() }}
+ {{ method.name.toCamelCase() }}: new this._gaxModule.ResumableUploadDescriptor(
+ '{{ method.resumableUpload.uploadPrefix }}'
+ )
+{%- endfor %}
+ };
+{%- endif %}
+
// Put together the default options sent with requests.
this._defaults = this._gaxGrpc.constructSettings(
'{{ api.naming.protoPackage }}.{{ service.name }}', gapicConfig as gax.ClientConfig,
@@ -447,10 +477,10 @@ export class {{ service.name }}Client {
(this._protos as any).{{api.naming.protoPackage}}.{{ service.name }},
this._opts, this._providedCustomServicePath) as Promise<{[method: string]: Function}>;
- {%- set stubMethodsContent %}
+{%- set stubMethodsContent %}
{%- set stubMethodsJoiner = joiner(', ') -%}
{%- for method in service.method -%}
- {%- if not method.ignoreMapPagingMethod %}
+ {%- if not method.ignoreMapPagingMethod and not method.resumableUpload %}
{{- stubMethodsJoiner() -}}
'{{ method.name.toCamelCase(true) }}'
{%- endif %}
@@ -508,6 +538,20 @@ export class {{ service.name }}Client {
this.innerApiCalls[methodName] = apiCall;
}
{%- endif -%}
+{%- if not api.legacyProtoLoad and service.resumableUploads.length > 0 %}
+
+ // Resumable upload methods do not use the gRPC/REST service stub; the
+ // The ResumableUploadSession performs its own HTTP requests.
+{%- for method in service.resumableUploads %}
+ this.innerApiCalls['{{ method.name.toCamelCase() }}'] =
+ this._gaxModule.createApiCall(
+ this._gaxModule.resumableUploadStub,
+ this._defaults['{{ method.name.toCamelCase() }}'],
+ this.descriptors.resumableUpload!['{{ method.name.toCamelCase() }}'],
+ this._opts.fallback
+ );
+{%- endfor %}
+{%- endif %}
{%- if service.options and service.options.deprecated %}
this.warn('DEP${{service.name}}', '{{service.name}} is deprecated and may be removed in a future version.', 'DeprecationWarning');
{%- endif %}
@@ -740,6 +784,78 @@ export class {{ service.name }}Client {
{%- endif %}
}
{%- endfor %}
+{%- if not api.legacyProtoLoad and service.resumableUploads.length > 0 %}
+ /**
+ * Creates a {@link gax.ResumableSource} backed by a local file.
+ *
+ * This delegates to google-gax so generated clients do not depend on the
+ * Node.js `fs` module at import time. The source can be passed as the
+ * `uploadSource` parameter of {@link gax.ResumableUploadSession#start}.
+ *
+ * @param {string} filePath - Path to the local file to upload.
+ * @returns {gax.ResumableSource} A seekable upload source for the file.
+ */
+ getResumableSource(filePath: string): gax.ResumableSource {
+ const gaxModule = this._gaxModule as typeof gax;
+ return gaxModule.resumableSourceFromFile(filePath);
+ }
+{%- endif %}
+{%- for method in service.resumableUploads %}
+{%- if not api.legacyProtoLoad %}
+/**
+ {{- internalWarning(service, method, api) }}
+{{- util.printCommentsForMethod(method) }}
+ {%- if method.options and method.options.deprecated %}
+ * @deprecated {{method.name}} is deprecated and may be removed in a future version.
+ {%- endif %}
+ * @param {object} [request] - The request object.
+ * @param {object} [options] - Optional parameters. The upload source, chunk
+ * size, progress callback, and resume URL are passed to
+ * {@link gax.ResumableUploadSession#start} instead.
+ * @returns {Promise} A resumable upload session.
+ * Call `.start(uploadParams)` with the source to upload, then await
+ * `.finished()` for the final RPC response.
+ */
+ {{ method.name.toCamelCase() }}(
+ request?: {{ util.toInterface(method.inputInterface) }},
+ options?: CallOptions): Promise {
+ request = request || {};
+ options = options || {};
+ if (!this._opts.fallback && this._opts.sslCreds) {
+ return Promise.reject(
+ new this._gaxModule.GoogleError(
+ 'Resumable upload methods require HTTP(S) authentication and ' +
+ 'cannot be used with gRPC channel credentials. Configure the ' +
+ 'client without `sslCreds`, or use `fallback: true`.',
+ ),
+ );
+ }
+ this.{{ id.get("initialize") }}().catch(err => {throw err});
+ {%- if method.options and method.options.deprecated %}
+ this.warn('DEP${{service.name}}-${{method.name}}','{{method.name}} is deprecated and may be removed in a future version.', 'DeprecationWarning');
+ {%- endif %}
+ this._log.info('{{ method.name.toCamelCase() }} request %j', request);
+ return (
+ this.innerApiCalls['{{ method.name.toCamelCase() }}'](request, {
+ ...options,
+ resumableUpload: {
+ auth: this._fallbackRest!.auth as gax.GoogleAuth,
+ servicePath: this._opts.servicePath ?? this._servicePath,
+ servicePort: this._opts.port || 443,
+ protocol: this._opts.protocol || 'https',
+ rpc: this._gaxModule.protobuf.Root.fromJSON(jsonProtos)
+ .lookupService('{{api.naming.protoPackage}}.{{ service.name }}')
+ .methods['{{ method.name }}'],
+ request,
+ uploadPrefix: '{{ method.resumableUpload.uploadPrefix }}',
+ numericEnums: this._opts.numericEnums,
+ minifyJson: this._opts.minifyJson,
+ },
+ }) as Promise<[gax.ResumableUploadSession]>
+ ).then(([session]) => session);
+ }
+{%- endif %}
+{%- endfor %}
{% for method in service.streaming %}
{%- if method.serverStreaming and method.clientStreaming %}
/**
@@ -1187,4 +1303,4 @@ export class {{ service.name }}Client {
}
return Promise.resolve();
}
-}
\ No newline at end of file
+}
diff --git a/core/generator/gapic-generator-typescript/templates/cjs/typescript_samples/samples/generated/$version/$service.$method.js.njk b/core/generator/gapic-generator-typescript/templates/cjs/typescript_samples/samples/generated/$version/$service.$method.js.njk
index 6d0301838663..81eedb26167c 100644
--- a/core/generator/gapic-generator-typescript/templates/cjs/typescript_samples/samples/generated/$version/$service.$method.js.njk
+++ b/core/generator/gapic-generator-typescript/templates/cjs/typescript_samples/samples/generated/$version/$service.$method.js.njk
@@ -94,6 +94,14 @@ function main({%- for comment in filteredComments -%}
stream.write(request);
stream.end();
}
+{% elif method.resumableUpload %}
+ // Run request
+ const session = await {{ (api.naming.productName).toCamelCase() }}Client.{{ method.name.toCamelCase() }}(request);
+ const uploadSource = {{ (api.naming.productName).toCamelCase() }}Client.getResumableSource('/path/to/file');
+ await session.start({uploadSource});
+ const response = await session.finished();
+ console.log(response);
+ }
{% else %}
// Run request
const response = await {{ (api.naming.productName).toCamelCase() }}Client.{{ method.name.toCamelCase() }}(request);
diff --git a/core/generator/gapic-generator-typescript/templates/esm/typescript_gapic/esm/src/$version/$service_client.ts.njk b/core/generator/gapic-generator-typescript/templates/esm/typescript_gapic/esm/src/$version/$service_client.ts.njk
index e61b45594482..42e7fc1ffd23 100644
--- a/core/generator/gapic-generator-typescript/templates/esm/typescript_gapic/esm/src/$version/$service_client.ts.njk
+++ b/core/generator/gapic-generator-typescript/templates/esm/typescript_gapic/esm/src/$version/$service_client.ts.njk
@@ -85,6 +85,9 @@ export class {{ service.name }}Client {
private _providedCustomServicePath: boolean;
private _gaxModule: typeof gax{% if not api.legacyProtoLoad %} | typeof gax.fallback{% endif %};
private _gaxGrpc: gax.GrpcClient{% if not api.legacyProtoLoad %} | gax.fallback.GrpcClient{% endif %};
+{%- if not api.legacyProtoLoad and service.resumableUploads.length > 0 %}
+ private _fallbackRest?: gax.GrpcClient | gax.fallback.GrpcClient;
+{%- endif %}
private _protos: {};
private _defaults: {[method: string]: gax.CallSettings};
private _universeDomain: string;
@@ -96,6 +99,9 @@ export class {{ service.name }}Client {
stream: {},
longrunning: {},
batching: {},
+{%- if not api.legacyProtoLoad and service.resumableUploads.length > 0 %}
+ resumableUpload: {},
+{%- endif %}
};
warn: (code: string, message: string, warnType?: string) => void;
innerApiCalls: {[name: string]: Function};
@@ -209,6 +215,15 @@ export class {{ service.name }}Client {
// Create a `gaxGrpc` object, with any grpc-specific options sent to the client.
this._gaxGrpc = new this._gaxModule.GrpcClient(opts);
+{%- if not api.legacyProtoLoad and service.resumableUploads.length > 0 %}
+
+ // This service contains resumable upload methods, which are HTTPS-only.
+ // Make sure the REST transport is available even when the client was
+ // configured for gRPC.
+ this._fallbackRest = opts.fallback
+ ? this._gaxGrpc
+ : new gaxInstance.fallback.GrpcClient({...opts, fallback: true});
+{%- endif %}
// Save options to use in {{ id.get("initialize") }}() method.
this._opts = opts;
@@ -410,6 +425,21 @@ export class {{ service.name }}Client {
};
{%- endif %}
+{%- if not api.legacyProtoLoad and service.resumableUploads.length > 0 %}
+
+ // Some methods on this API support resumable uploads; provide
+ // descriptors for these methods.
+ this.descriptors.resumableUpload = {
+{%- set resumableUploadJoiner = joiner() %}
+{%- for method in service.resumableUploads %}
+ {{- resumableUploadJoiner() }}
+ {{ method.name.toCamelCase() }}: new this._gaxModule.ResumableUploadDescriptor(
+ '{{ method.resumableUpload.uploadPrefix }}'
+ )
+{%- endfor %}
+ };
+{%- endif %}
+
// Put together the default options sent with requests.
this._defaults = this._gaxGrpc.constructSettings(
'{{ api.naming.protoPackage }}.{{ service.name }}', gapicConfig as gax.ClientConfig,
@@ -458,10 +488,10 @@ export class {{ service.name }}Client {
(this._protos as any).{{api.naming.protoPackage}}.{{ service.name }},
this._opts, this._providedCustomServicePath) as Promise<{[method: string]: Function}>;
- {%- set stubMethodsContent %}
+{%- set stubMethodsContent %}
{%- set stubMethodsJoiner = joiner(', ') -%}
{%- for method in service.method -%}
- {%- if not method.ignoreMapPagingMethod %}
+ {%- if not method.ignoreMapPagingMethod and not method.resumableUpload %}
{{- stubMethodsJoiner() -}}
'{{ method.name.toCamelCase(true) }}'
{%- endif %}
@@ -519,6 +549,20 @@ export class {{ service.name }}Client {
this.innerApiCalls[methodName] = apiCall;
}
{%- endif -%}
+{%- if not api.legacyProtoLoad and service.resumableUploads.length > 0 %}
+
+ // Resumable upload methods do not use the gRPC/REST service stub; the
+ // The ResumableUploadSession performs its own HTTP requests.
+{%- for method in service.resumableUploads %}
+ this.innerApiCalls['{{ method.name.toCamelCase() }}'] =
+ this._gaxModule.createApiCall(
+ this._gaxModule.resumableUploadStub,
+ this._defaults['{{ method.name.toCamelCase() }}'],
+ this.descriptors.resumableUpload!['{{ method.name.toCamelCase() }}'],
+ this._opts.fallback
+ );
+{%- endfor %}
+{%- endif %}
{%- if service.options and service.options.deprecated %}
this.warn('DEP${{service.name}}', '{{service.name}} is deprecated and may be removed in a future version.', 'DeprecationWarning');
{%- endif %}
@@ -751,6 +795,78 @@ export class {{ service.name }}Client {
{%- endif %}
}
{%- endfor %}
+{%- if not api.legacyProtoLoad and service.resumableUploads.length > 0 %}
+ /**
+ * Creates a {@link gax.ResumableSource} backed by a local file.
+ *
+ * This delegates to google-gax so generated clients do not depend on the
+ * Node.js `fs` module at import time. The source can be passed as the
+ * `uploadSource` parameter of {@link gax.ResumableUploadSession#start}.
+ *
+ * @param {string} filePath - Path to the local file to upload.
+ * @returns {gax.ResumableSource} A seekable upload source for the file.
+ */
+ getResumableSource(filePath: string): gax.ResumableSource {
+ const gaxModule = this._gaxModule as typeof gax;
+ return gaxModule.resumableSourceFromFile(filePath);
+ }
+{%- endif %}
+{%- for method in service.resumableUploads %}
+{%- if not api.legacyProtoLoad %}
+/**
+ {{- internalWarning(service, method, api) }}
+{{- util.printCommentsForMethod(method) }}
+ {%- if method.options and method.options.deprecated %}
+ * @deprecated {{method.name}} is deprecated and may be removed in a future version.
+ {%- endif %}
+ * @param {object} [request] - The request object.
+ * @param {object} [options] - Optional parameters. The upload source, chunk
+ * size, progress callback, and resume URL are passed to
+ * {@link gax.ResumableUploadSession#start} instead.
+ * @returns {Promise} A resumable upload session.
+ * Call `.start(uploadParams)` with the source to upload, then await
+ * `.finished()` for the final RPC response.
+ */
+ {{ method.name.toCamelCase() }}(
+ request?: {{ util.toInterface(method.inputInterface) }},
+ options?: CallOptions): Promise {
+ request = request || {};
+ options = options || {};
+ if (!this._opts.fallback && this._opts.sslCreds) {
+ return Promise.reject(
+ new this._gaxModule.GoogleError(
+ 'Resumable upload methods require HTTP(S) authentication and ' +
+ 'cannot be used with gRPC channel credentials. Configure the ' +
+ 'client without `sslCreds`, or use `fallback: true`.',
+ ),
+ );
+ }
+ this.{{ id.get("initialize") }}().catch(err => {throw err});
+ {%- if method.options and method.options.deprecated %}
+ this.warn('DEP${{service.name}}-${{method.name}}','{{method.name}} is deprecated and may be removed in a future version.', 'DeprecationWarning');
+ {%- endif %}
+ this._log.info('{{ method.name.toCamelCase() }} request %j', request);
+ return (
+ this.innerApiCalls['{{ method.name.toCamelCase() }}'](request, {
+ ...options,
+ resumableUpload: {
+ auth: this._fallbackRest!.auth as gax.GoogleAuth,
+ servicePath: this._opts.servicePath ?? this._servicePath,
+ servicePort: this._opts.port || 443,
+ protocol: this._opts.protocol || 'https',
+ rpc: this._gaxModule.protobuf.Root.fromJSON(jsonProtos)
+ .lookupService('{{api.naming.protoPackage}}.{{ service.name }}')
+ .methods['{{ method.name }}'],
+ request,
+ uploadPrefix: '{{ method.resumableUpload.uploadPrefix }}',
+ numericEnums: this._opts.numericEnums,
+ minifyJson: this._opts.minifyJson,
+ },
+ }) as Promise<[gax.ResumableUploadSession]>
+ ).then(([session]) => session);
+ }
+{%- endif %}
+{%- endfor %}
{% for method in service.streaming %}
{%- if method.serverStreaming and method.clientStreaming %}
/**
@@ -1194,4 +1310,4 @@ export class {{ service.name }}Client {
}
return Promise.resolve();
}
-}
\ No newline at end of file
+}
diff --git a/core/generator/gapic-generator-typescript/templates/esm/typescript_samples/samples/generated/$version/$service.$method.js.njk b/core/generator/gapic-generator-typescript/templates/esm/typescript_samples/samples/generated/$version/$service.$method.js.njk
index 6d0301838663..81eedb26167c 100644
--- a/core/generator/gapic-generator-typescript/templates/esm/typescript_samples/samples/generated/$version/$service.$method.js.njk
+++ b/core/generator/gapic-generator-typescript/templates/esm/typescript_samples/samples/generated/$version/$service.$method.js.njk
@@ -94,6 +94,14 @@ function main({%- for comment in filteredComments -%}
stream.write(request);
stream.end();
}
+{% elif method.resumableUpload %}
+ // Run request
+ const session = await {{ (api.naming.productName).toCamelCase() }}Client.{{ method.name.toCamelCase() }}(request);
+ const uploadSource = {{ (api.naming.productName).toCamelCase() }}Client.getResumableSource('/path/to/file');
+ await session.start({uploadSource});
+ const response = await session.finished();
+ console.log(response);
+ }
{% else %}
// Run request
const response = await {{ (api.naming.productName).toCamelCase() }}Client.{{ method.name.toCamelCase() }}(request);
diff --git a/core/generator/gapic-generator-typescript/test-fixtures/protos/google/samples/resumable/v1/resumable.proto b/core/generator/gapic-generator-typescript/test-fixtures/protos/google/samples/resumable/v1/resumable.proto
new file mode 100644
index 000000000000..c5980d756f9d
--- /dev/null
+++ b/core/generator/gapic-generator-typescript/test-fixtures/protos/google/samples/resumable/v1/resumable.proto
@@ -0,0 +1,72 @@
+// Copyright 2026 Google LLC
+//
+// Licensed 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.
+
+// Synthetic fixture used by the baseline tests to exercise resumable upload
+// method generation via the resumable_upload_methods generator parameter.
+
+syntax = "proto3";
+
+package google.samples.resumable.v1;
+
+import "google/api/annotations.proto";
+import "google/api/client.proto";
+
+option csharp_namespace = "Google.Samples.Resumable.V1";
+option go_package = "google.golang.org/genproto/googleapis/samples/resumable/v1;resumable";
+option java_multiple_files = true;
+option java_outer_classname = "ResumableProto";
+option java_package = "com.google.samples.resumable.v1";
+option php_namespace = "Google\\Samples\\Resumable\\V1";
+option ruby_package = "Google::Samples::Resumable::V1";
+
+service ResumableUploadService {
+ option (google.api.default_host) = "resumable.googleapis.com";
+ option (google.api.oauth_scopes) =
+ "https://www.googleapis.com/auth/cloud-platform";
+
+ // Creates a resumable upload session.
+ rpc CreateResumableUpload(CreateResumableUploadRequest)
+ returns (CreateResumableUploadResponse) {
+ option (google.api.http) = {
+ post: "/v1/uploads"
+ body: "*"
+ };
+ }
+
+ // Returns the status of a previously created upload session.
+ rpc GetUploadStatus(GetUploadStatusRequest)
+ returns (GetUploadStatusResponse) {
+ option (google.api.http) = {
+ get: "/v1/uploads/{upload_url}"
+ };
+ }
+}
+
+message CreateResumableUploadRequest {
+ string name = 1;
+ string description = 2;
+}
+
+message CreateResumableUploadResponse {
+ string upload_url = 1;
+ string status = 2;
+}
+
+message GetUploadStatusRequest {
+ string upload_url = 1;
+}
+
+message GetUploadStatusResponse {
+ string status = 1;
+}
diff --git a/core/generator/gapic-generator-typescript/typescript/src/gapic-generator-typescript.ts b/core/generator/gapic-generator-typescript/typescript/src/gapic-generator-typescript.ts
index 86f94791dc57..4f59b199fe1c 100755
--- a/core/generator/gapic-generator-typescript/typescript/src/gapic-generator-typescript.ts
+++ b/core/generator/gapic-generator-typescript/typescript/src/gapic-generator-typescript.ts
@@ -136,6 +136,12 @@ async function main(processArgv: string[]) {
'Override the list of mixins to use. Semicolon-separated list of API names to mixin, e.g. google.longrunning.Operations. Use "none" to disable all mixins.',
)
.string('mixins')
+ .describe(
+ 'resumable_upload_methods',
+ 'Semicolon-separated list of ServiceName.MethodName pairs that should be treated as resumable upload methods, e.g. ResumableUploadService.CreateResumableUpload.',
+ )
+ .string('resumable_upload_methods')
+ .alias('resumable_upload_methods', 'resumable-upload-methods')
.describe('protoc', 'Path to protoc binary')
.usage('Usage: $0 -I /path/to/googleapis')
.usage(' --output_dir /path/to/output_directory')
@@ -158,6 +164,9 @@ async function main(processArgv: string[]) {
const legacyProtoLoad = argv.legacyProtoLoad as boolean | undefined;
const restNumericEnums = argv.restNumericEnums as boolean | undefined;
const mixins = argv.mixins as string | undefined;
+ const resumableUploadMethods = argv.resumableUploadMethods as
+ | string
+ | undefined;
// --protoc can be taken from environment or from the command line
let protocParameter = argv.protoc as string | string[] | undefined;
@@ -247,6 +256,11 @@ async function main(processArgv: string[]) {
if (mixins) {
protocCommand.push(`--typescript_gapic_opt="mixins=${mixins}"`);
}
+ if (resumableUploadMethods) {
+ protocCommand.push(
+ `--typescript_gapic_opt="resumable-upload-methods=${resumableUploadMethods}"`,
+ );
+ }
protocCommand.push(...protoDirsArg);
protocCommand.push(...protoFiles);
protocCommand.push(`-I${commonProtoPath}`);
diff --git a/core/generator/gapic-generator-typescript/typescript/src/generator.ts b/core/generator/gapic-generator-typescript/typescript/src/generator.ts
index b66849bed378..4f0c068d2a93 100644
--- a/core/generator/gapic-generator-typescript/typescript/src/generator.ts
+++ b/core/generator/gapic-generator-typescript/typescript/src/generator.ts
@@ -85,6 +85,7 @@ export class Generator {
legacyProtoLoad?: boolean;
restNumericEnums?: boolean;
mixinsOverride?: string[];
+ resumableUploadMethods?: string[];
format?: string | string[];
enableTelemetryTracing?: boolean;
@@ -252,6 +253,15 @@ export class Generator {
}
}
+ private readResumableUploadMethods() {
+ if (this.paramMap['resumable-upload-methods']) {
+ this.resumableUploadMethods = this.paramMap['resumable-upload-methods']
+ .split(';')
+ .map(name => name.trim())
+ .filter(name => name.length > 0);
+ }
+ }
+
async initializeFromStdin() {
const inputBuffer = await getStdin();
const CodeGeneratorRequest = this.root.lookupType('CodeGeneratorRequest');
@@ -282,6 +292,7 @@ export class Generator {
this.readRestNumericEnums();
this.readFormat();
this.readEnableTelemetryTracing();
+ this.readResumableUploadMethods();
}
}
@@ -343,6 +354,7 @@ export class Generator {
restNumericEnums: this.restNumericEnums,
mixinsOverridden: this.mixinsOverride !== undefined,
enableTelemetryTracing: this.enableTelemetryTracing,
+ resumableUploadMethods: this.resumableUploadMethods,
});
return api;
}
diff --git a/core/generator/gapic-generator-typescript/typescript/src/schema/api.ts b/core/generator/gapic-generator-typescript/typescript/src/schema/api.ts
index 2e8c02aadc69..e424cc2c36f5 100644
--- a/core/generator/gapic-generator-typescript/typescript/src/schema/api.ts
+++ b/core/generator/gapic-generator-typescript/typescript/src/schema/api.ts
@@ -43,6 +43,7 @@ export class API {
handwrittenLayer?: boolean;
legacyProtoLoad: boolean;
restNumericEnums: boolean;
+ resumableUploadMethods: string[];
documentationUri: any;
newIssueUri: string;
enableTelemetryTracing?: boolean;
@@ -110,6 +111,7 @@ export class API {
this.diregapic = options.diregapic ?? false;
this.legacyProtoLoad = options.legacyProtoLoad ?? false;
this.restNumericEnums = options.restNumericEnums ?? false;
+ this.resumableUploadMethods = options.resumableUploadMethods ?? [];
this.documentationUri =
options.serviceYaml?.publishing?.documentation_uri ?? '';
this.newIssueUri = options.serviceYaml?.publishing?.new_issue_uri ?? '';
diff --git a/core/generator/gapic-generator-typescript/typescript/src/schema/naming.ts b/core/generator/gapic-generator-typescript/typescript/src/schema/naming.ts
index 49c90c9f1b63..06cc8a18c473 100644
--- a/core/generator/gapic-generator-typescript/typescript/src/schema/naming.ts
+++ b/core/generator/gapic-generator-typescript/typescript/src/schema/naming.ts
@@ -31,6 +31,7 @@ export interface Options {
restNumericEnums?: boolean;
mixinsOverridden?: boolean;
enableTelemetryTracing?: boolean;
+ resumableUploadMethods?: string[];
}
export class Naming {
diff --git a/core/generator/gapic-generator-typescript/typescript/src/schema/proto.ts b/core/generator/gapic-generator-typescript/typescript/src/schema/proto.ts
index 60c6673b67bd..04a89800c73f 100644
--- a/core/generator/gapic-generator-typescript/typescript/src/schema/proto.ts
+++ b/core/generator/gapic-generator-typescript/typescript/src/schema/proto.ts
@@ -79,6 +79,9 @@ export interface MethodDescriptorProto
bundleConfig?: BundleConfig;
toJSON: Function | undefined;
isDiregapicLRO?: boolean;
+ // If set, the method opts into the resumable upload protocol
+ // via the resumable_upload_methods generator parameter.
+ resumableUpload?: {uploadPrefix: string} | undefined;
// if wrappers are allowed and there is a maxResultsParamter, return true
maxResultsParameter?: boolean;
}
@@ -138,6 +141,7 @@ export interface ServiceDescriptorProto
longRunningOperationsMixinFlags?: OperationsMixinConfig;
protoFile: string;
diregapicLRO?: MethodDescriptorProto[];
+ resumableUploads: MethodDescriptorProto[];
httpRules?: protos.google.api.IHttpRule[];
selectiveGapic: SelectiveGapicConfig;
}
@@ -303,6 +307,24 @@ function streaming(method: MethodDescriptorProto) {
return undefined;
}
+// Methods selected with the resumable_upload_methods generator parameter use
+// the default upload prefix, since the parameter only identifies methods.
+const DEFAULT_RESUMABLE_UPLOAD_PREFIX = '/resumable/upload';
+
+function resumableUploadMethodNames(
+ serviceName: string,
+ resumableUploadMethods: string[] | undefined,
+): Set {
+ const servicePrefix = `${serviceName}.`;
+ const methodNames = new Set();
+ for (const methodName of resumableUploadMethods ?? []) {
+ if (methodName.startsWith(servicePrefix)) {
+ methodNames.add(methodName.substring(servicePrefix.length));
+ }
+ }
+ return methodNames;
+}
+
// returns true if the method has wrappers for UInt32Value enabled
// and is a paginated call with a maxResults parameter instead of pageSize
// as of its creation, this should only be true for BigQuery
@@ -1031,9 +1053,13 @@ export function augmentService(parameters: AugmentServiceParameters) {
augmentedService.bundleConfigs = parameters.options.bundleConfigs?.filter(
bc => bc.serviceName === parameters.service.name,
);
+ const resumableUploadMethods = resumableUploadMethodNames(
+ parameters.service.name!,
+ parameters.options.resumableUploadMethods,
+ );
augmentedService.method =
- augmentedService.method?.map(method =>
- augmentMethod(
+ augmentedService.method?.map(method => {
+ const augmentedMethod = augmentMethod(
{
allMessages: parameters.allMessages,
localMessages: parameters.localMessages,
@@ -1041,8 +1067,14 @@ export function augmentService(parameters: AugmentServiceParameters) {
diregapic: parameters.options.diregapic,
},
method,
- ),
- ) ?? [];
+ );
+ if (resumableUploadMethods.has(augmentedMethod.name!)) {
+ augmentedMethod.resumableUpload = {
+ uploadPrefix: DEFAULT_RESUMABLE_UPLOAD_PREFIX,
+ };
+ }
+ return augmentedMethod;
+ }) ?? [];
/* Selective GAPIC method handling. */
augmentedService.method = augmentedService.method.filter(
@@ -1076,7 +1108,13 @@ export function augmentService(parameters: AugmentServiceParameters) {
);
augmentedService.simpleMethods = augmentedService.method.filter(
method =>
- !method.longRunning && !method.streaming && !method.pagingFieldName,
+ !method.longRunning &&
+ !method.streaming &&
+ !method.pagingFieldName &&
+ !method.resumableUpload,
+ );
+ augmentedService.resumableUploads = augmentedService.method.filter(
+ method => method.resumableUpload,
);
augmentedService.longRunning = augmentedService.method.filter(
method => method.longRunning,
diff --git a/core/generator/gapic-generator-typescript/typescript/test/unit/api.ts b/core/generator/gapic-generator-typescript/typescript/test/unit/api.ts
index 0fddfb7f3e71..e0d67fe1e97a 100644
--- a/core/generator/gapic-generator-typescript/typescript/test/unit/api.ts
+++ b/core/generator/gapic-generator-typescript/typescript/test/unit/api.ts
@@ -36,6 +36,40 @@ describe('src/schema/api.ts', () => {
]);
});
+ it('should expose resumable upload methods passed as options', () => {
+ const fd = {} as protos.google.protobuf.FileDescriptorProto;
+ fd.name = 'google/cloud/test/v1/test.proto';
+ fd.package = 'google.cloud.test.v1';
+ fd.service = [{} as protos.google.protobuf.ServiceDescriptorProto];
+ fd.service[0].name = 'ZService';
+ fd.service[0].options = {
+ '.google.api.defaultHost': 'hostname.example.com:443',
+ };
+ const api = new API([fd], 'google.cloud.test.v1', {
+ grpcServiceConfig: {} as protos.grpc.service_config.ServiceConfig,
+ resumableUploadMethods: ['ZService.Upload', 'ZService.Resume'],
+ });
+ assert.deepStrictEqual(api.resumableUploadMethods, [
+ 'ZService.Upload',
+ 'ZService.Resume',
+ ]);
+ });
+
+ it('should default resumable upload methods to an empty array', () => {
+ const fd = {} as protos.google.protobuf.FileDescriptorProto;
+ fd.name = 'google/cloud/test/v1/test.proto';
+ fd.package = 'google.cloud.test.v1';
+ fd.service = [{} as protos.google.protobuf.ServiceDescriptorProto];
+ fd.service[0].name = 'ZService';
+ fd.service[0].options = {
+ '.google.api.defaultHost': 'hostname.example.com:443',
+ };
+ const api = new API([fd], 'google.cloud.test.v1', {
+ grpcServiceConfig: {} as protos.grpc.service_config.ServiceConfig,
+ });
+ assert.deepStrictEqual(api.resumableUploadMethods, []);
+ });
+
it('should correctly derive a valid logging name', () => {
const fd = {} as protos.google.protobuf.FileDescriptorProto;
fd.name = 'google/cloud/test/v1/test.proto';
diff --git a/core/generator/gapic-generator-typescript/typescript/test/unit/baselines-esm.ts b/core/generator/gapic-generator-typescript/typescript/test/unit/baselines-esm.ts
index 229527063d73..e2288775ddae 100644
--- a/core/generator/gapic-generator-typescript/typescript/test/unit/baselines-esm.ts
+++ b/core/generator/gapic-generator-typescript/typescript/test/unit/baselines-esm.ts
@@ -32,6 +32,14 @@ describe('Baseline tests: ESM', () => {
useCommonProto: true,
format: 'esm',
});
+ runBaselineTest({
+ baselineName: 'resumable-upload-esm',
+ outputDir: '.test-out-resumable-upload-esm',
+ protoPath: 'google/samples/resumable/v1/resumable.proto',
+ useCommonProto: false,
+ format: 'esm',
+ resumableUploadMethods: 'ResumableUploadService.CreateResumableUpload',
+ });
runBaselineTest({
baselineName: 'dlp-esm',
outputDir: '.test-out-dlp-esm',
diff --git a/core/generator/gapic-generator-typescript/typescript/test/unit/baselines.ts b/core/generator/gapic-generator-typescript/typescript/test/unit/baselines.ts
index d1638762b508..b172d72596c4 100644
--- a/core/generator/gapic-generator-typescript/typescript/test/unit/baselines.ts
+++ b/core/generator/gapic-generator-typescript/typescript/test/unit/baselines.ts
@@ -30,6 +30,13 @@ describe('Baseline tests', () => {
'google/duplicatemethodstest/v1/duplicate_methods_test_v1.yaml',
useCommonProto: true,
});
+ runBaselineTest({
+ baselineName: 'resumable-upload',
+ outputDir: '.test-out-resumable-upload',
+ protoPath: 'google/samples/resumable/v1/resumable.proto',
+ useCommonProto: false,
+ resumableUploadMethods: 'ResumableUploadService.CreateResumableUpload',
+ });
runBaselineTest({
baselineName: 'dlp',
outputDir: '.test-out-dlp',
diff --git a/core/generator/gapic-generator-typescript/typescript/test/unit/proto.ts b/core/generator/gapic-generator-typescript/typescript/test/unit/proto.ts
index fd1427cbe458..ab17a984aae0 100644
--- a/core/generator/gapic-generator-typescript/typescript/test/unit/proto.ts
+++ b/core/generator/gapic-generator-typescript/typescript/test/unit/proto.ts
@@ -1794,3 +1794,96 @@ describe('src/schema/proto.ts', () => {
});
});
});
+
+describe('src/schema/proto.ts - resumable upload methods', () => {
+ function augmentResumableTestService(resumableUploadMethods?: string[]) {
+ const fd = {} as protos.google.protobuf.FileDescriptorProto;
+ fd.package = 'google.samples.resumable.v1';
+ fd.service = [{} as protos.google.protobuf.ServiceDescriptorProto];
+ fd.service[0].name = 'ResumableUploadService';
+ fd.service[0].method = [
+ {
+ name: 'CreateResumableUpload',
+ inputType: '.google.samples.resumable.v1.CreateResumableUploadRequest',
+ outputType:
+ '.google.samples.resumable.v1.CreateResumableUploadResponse',
+ },
+ {
+ name: 'GetUploadStatus',
+ inputType: '.google.samples.resumable.v1.GetUploadStatusRequest',
+ outputType: '.google.samples.resumable.v1.GetUploadStatusResponse',
+ },
+ ] as protos.google.protobuf.MethodDescriptorProto[];
+
+ const options: Options = {
+ grpcServiceConfig: {} as protos.grpc.service_config.ServiceConfig,
+ resumableUploadMethods,
+ };
+ return augmentService({
+ allMessages: {},
+ localMessages: {},
+ packageName: 'google.samples.resumable.v1',
+ service: fd.service[0],
+ commentsMap: new CommentsMap([fd]),
+ allResourceDatabase: new ResourceDatabase(),
+ resourceDatabase: new ResourceDatabase(),
+ options,
+ protoFile: 'fd',
+ });
+ }
+
+ it('marks methods listed in resumableUploadMethods', () => {
+ const augmentedService = augmentResumableTestService([
+ 'OtherService.DoNotEnable',
+ 'ResumableUploadService.CreateResumableUpload',
+ ]);
+
+ assert.strictEqual(augmentedService.resumableUploads.length, 1);
+ assert.deepStrictEqual(
+ augmentedService.resumableUploads[0].resumableUpload,
+ {uploadPrefix: '/resumable/upload'},
+ );
+ assert.strictEqual(
+ augmentedService.method.find(m => m.name === 'GetUploadStatus')
+ ?.resumableUpload,
+ undefined,
+ );
+ assert.strictEqual(
+ augmentedService.simpleMethods.some(
+ m => m.name === 'CreateResumableUpload',
+ ),
+ false,
+ );
+ assert.strictEqual(
+ augmentedService.simpleMethods.some(m => m.name === 'GetUploadStatus'),
+ true,
+ );
+ });
+
+ it('does not enable methods that are not listed for the service', () => {
+ const augmentedService = augmentResumableTestService([
+ 'ResumableUploadService.CreateResumableUpload',
+ ]);
+
+ assert.strictEqual(
+ augmentedService.method.find(m => m.name === 'GetUploadStatus')
+ ?.resumableUpload,
+ undefined,
+ );
+ assert.strictEqual(
+ augmentedService.simpleMethods.some(m => m.name === 'GetUploadStatus'),
+ true,
+ );
+ });
+
+ it('does not enable resumable uploads when the option is omitted', () => {
+ const augmentedService = augmentResumableTestService();
+
+ assert.strictEqual(augmentedService.resumableUploads.length, 0);
+ assert.strictEqual(
+ augmentedService.method.find(m => m.name === 'CreateResumableUpload')
+ ?.resumableUpload,
+ undefined,
+ );
+ });
+});
diff --git a/core/generator/gapic-generator-typescript/typescript/test/util.ts b/core/generator/gapic-generator-typescript/typescript/test/util.ts
index 617a44463c02..698dba12a4bf 100644
--- a/core/generator/gapic-generator-typescript/typescript/test/util.ts
+++ b/core/generator/gapic-generator-typescript/typescript/test/util.ts
@@ -46,6 +46,7 @@ export interface BaselineOptions {
diregapic?: boolean;
restNumericEnums?: boolean;
mixins?: string;
+ resumableUploadMethods?: string;
format?: string;
}
@@ -147,6 +148,9 @@ export function runBaselineTest(options: BaselineOptions) {
if (options.mixins) {
commandLine += ` --mixins="${options.mixins}"`;
}
+ if (options.resumableUploadMethods) {
+ commandLine += ` --resumable_upload_methods="${options.resumableUploadMethods}"`;
+ }
execSync(commandLine);
assert(equalToBaseline(outputDir, baselineDir));
});