diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index dbc9e2fa5a3..beabb887c67 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,4 +1,5 @@
{
+ "handwritten/nodejs-promisify": "5.0.0",
"packages/gapic-node-processing": "0.1.6",
"packages/google-ads-admanager": "0.5.0",
"packages/google-ads-datamanager": "0.1.0",
@@ -23,6 +24,7 @@
"packages/google-cloud-apigeeconnect": "4.2.1",
"packages/google-cloud-apigeeregistry": "2.2.1",
"packages/google-cloud-apihub": "0.5.1",
+ "packages/google-cloud-apiregistry": "0.1.0",
"packages/google-cloud-apphub": "0.6.1",
"packages/google-cloud-asset": "6.3.1",
"packages/google-cloud-assuredworkloads": "5.1.1",
@@ -92,6 +94,7 @@
"packages/google-cloud-gkeconnect-gateway": "5.2.1",
"packages/google-cloud-gkehub": "6.3.1",
"packages/google-cloud-gkemulticloud": "2.3.0",
+ "packages/google-cloud-gkerecommender": "0.1.0",
"packages/google-cloud-gsuiteaddons": "2.2.1",
"packages/google-cloud-hypercomputecluster": "0.1.0",
"packages/google-cloud-iap": "4.3.1",
@@ -145,11 +148,11 @@
"packages/google-cloud-saasplatform-saasservicemgmt": "0.1.1",
"packages/google-cloud-scheduler": "5.3.1",
"packages/google-cloud-secretmanager": "6.1.1",
+ "packages/google-cloud-securesourcemanager": "0.8.1",
"packages/google-cloud-security-privateca": "7.0.1",
"packages/google-cloud-security-publicca": "2.2.1",
"packages/google-cloud-securitycenter": "9.2.1",
"packages/google-cloud-securitycentermanagement": "0.7.1",
- "packages/google-cloud-securesourcemanager": "0.8.1",
"packages/google-cloud-servicedirectory": "6.1.1",
"packages/google-cloud-servicehealth": "0.7.1",
"packages/google-cloud-shell": "4.1.1",
@@ -216,7 +219,5 @@
"packages/google-storagetransfer": "4.2.1",
"packages/google-streetview-publish": "0.4.1",
"packages/grafeas": "6.1.1",
- "packages/typeless-sample-bot": "3.1.1",
- "packages/google-cloud-apiregistry": "0.1.0",
- "packages/google-cloud-gkerecommender": "0.1.0"
-}
\ No newline at end of file
+ "packages/typeless-sample-bot": "3.1.1"
+}
diff --git a/handwritten/nodejs-promisify/.compodocrc b/handwritten/nodejs-promisify/.compodocrc
new file mode 100644
index 00000000000..cd8b42152a6
--- /dev/null
+++ b/handwritten/nodejs-promisify/.compodocrc
@@ -0,0 +1,10 @@
+---
+tsconfig: ./tsconfig.json
+output: ./docs
+theme: material
+hideGenerator: true
+disablePrivate: true
+disableProtected: true
+disableInternal: true
+disableCoverage: true
+disableGraph: true
diff --git a/handwritten/nodejs-promisify/.eslintignore b/handwritten/nodejs-promisify/.eslintignore
new file mode 100644
index 00000000000..c4a0963e9bd
--- /dev/null
+++ b/handwritten/nodejs-promisify/.eslintignore
@@ -0,0 +1,8 @@
+**/node_modules
+**/coverage
+test/fixtures
+build/
+docs/
+protos/
+samples/generated/
+system-test/**/fixtures
diff --git a/handwritten/nodejs-promisify/.eslintrc.json b/handwritten/nodejs-promisify/.eslintrc.json
new file mode 100644
index 00000000000..78215349546
--- /dev/null
+++ b/handwritten/nodejs-promisify/.eslintrc.json
@@ -0,0 +1,3 @@
+{
+ "extends": "./node_modules/gts"
+}
diff --git a/handwritten/nodejs-promisify/.gitattributes b/handwritten/nodejs-promisify/.gitattributes
new file mode 100644
index 00000000000..33739cb74e4
--- /dev/null
+++ b/handwritten/nodejs-promisify/.gitattributes
@@ -0,0 +1,4 @@
+*.ts text eol=lf
+*.js text eol=lf
+protos/* linguist-generated
+**/api-extractor.json linguist-language=JSON-with-Comments
diff --git a/handwritten/nodejs-promisify/.gitignore b/handwritten/nodejs-promisify/.gitignore
new file mode 100644
index 00000000000..a55e9556d64
--- /dev/null
+++ b/handwritten/nodejs-promisify/.gitignore
@@ -0,0 +1,8 @@
+node_modules
+build
+docs
+.nyc_output
+package-lock.json
+.vscode
+__pycache__
+.coverage
diff --git a/handwritten/nodejs-promisify/.jsdoc.js b/handwritten/nodejs-promisify/.jsdoc.js
new file mode 100644
index 00000000000..9af25f239ef
--- /dev/null
+++ b/handwritten/nodejs-promisify/.jsdoc.js
@@ -0,0 +1,51 @@
+// Copyright 2019 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.
+//
+
+'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'
+ ],
+ includePattern: '\\.js$'
+ },
+ templates: {
+ copyright: 'Copyright 2019 Google, LLC.',
+ includeDate: false,
+ sourceFiles: false,
+ systemName: '@google-cloud/promisify',
+ theme: 'lumen',
+ default: {
+ "outputSourceFiles": false
+ }
+ },
+ markdown: {
+ idInHeadings: true
+ }
+};
diff --git a/handwritten/nodejs-promisify/.mocharc.js b/handwritten/nodejs-promisify/.mocharc.js
new file mode 100644
index 00000000000..0b600509bed
--- /dev/null
+++ b/handwritten/nodejs-promisify/.mocharc.js
@@ -0,0 +1,29 @@
+// Copyright 2020 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.
+const config = {
+ "enable-source-maps": true,
+ "throw-deprecation": true,
+ "timeout": 10000,
+ "recursive": true
+}
+if (process.env.MOCHA_THROW_DEPRECATION === 'false') {
+ delete config['throw-deprecation'];
+}
+if (process.env.MOCHA_REPORTER) {
+ config.reporter = process.env.MOCHA_REPORTER;
+}
+if (process.env.MOCHA_REPORTER_OUTPUT) {
+ config['reporter-option'] = `output=${process.env.MOCHA_REPORTER_OUTPUT}`;
+}
+module.exports = config
diff --git a/handwritten/nodejs-promisify/.nycrc b/handwritten/nodejs-promisify/.nycrc
new file mode 100644
index 00000000000..b18d5472b62
--- /dev/null
+++ b/handwritten/nodejs-promisify/.nycrc
@@ -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
+}
diff --git a/handwritten/nodejs-promisify/.prettierignore b/handwritten/nodejs-promisify/.prettierignore
new file mode 100644
index 00000000000..9340ad9b86d
--- /dev/null
+++ b/handwritten/nodejs-promisify/.prettierignore
@@ -0,0 +1,6 @@
+**/node_modules
+**/coverage
+test/fixtures
+build/
+docs/
+protos/
diff --git a/handwritten/nodejs-promisify/.prettierrc.js b/handwritten/nodejs-promisify/.prettierrc.js
new file mode 100644
index 00000000000..d1b95106f4c
--- /dev/null
+++ b/handwritten/nodejs-promisify/.prettierrc.js
@@ -0,0 +1,17 @@
+// Copyright 2020 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.
+
+module.exports = {
+ ...require('gts/.prettierrc.json')
+}
diff --git a/handwritten/nodejs-promisify/.readme-partials.yaml b/handwritten/nodejs-promisify/.readme-partials.yaml
new file mode 100644
index 00000000000..89520d55eac
--- /dev/null
+++ b/handwritten/nodejs-promisify/.readme-partials.yaml
@@ -0,0 +1,3 @@
+body: |-
+ It's unlikely you will need to install this package directly, as it will be
+ installed as a dependency when you install other `@google-cloud` packages.
diff --git a/handwritten/nodejs-promisify/.repo-metadata.json b/handwritten/nodejs-promisify/.repo-metadata.json
new file mode 100644
index 00000000000..5577db1dad5
--- /dev/null
+++ b/handwritten/nodejs-promisify/.repo-metadata.json
@@ -0,0 +1,12 @@
+{
+ "repo": "googleapis/google-cloud-node",
+ "distribution_name": "@google-cloud/promisify",
+ "language": "nodejs",
+ "release_level": "stable",
+ "client_documentation": "https://googleapis.dev/nodejs/promisify/latest",
+ "name_pretty": "Google Cloud Common Promisify",
+ "name": "promisify",
+ "api_shortname": "promisify",
+ "library_type": "OTHER",
+ "codeowner_team": "@googleapis/jsteam-handwritten-libraries"
+}
diff --git a/handwritten/nodejs-promisify/CHANGELOG.md b/handwritten/nodejs-promisify/CHANGELOG.md
new file mode 100644
index 00000000000..97a53a526c5
--- /dev/null
+++ b/handwritten/nodejs-promisify/CHANGELOG.md
@@ -0,0 +1,209 @@
+# Changelog
+
+[npm history][1]
+
+[1]: https://www.npmjs.com/package/nodejs-promisify?activeTab=versions
+
+## [5.0.0](https://github.com/googleapis/nodejs-promisify/compare/v4.1.0...v5.0.0) (2025-03-11)
+
+
+### ⚠ BREAKING CHANGES
+
+* upgrade to Node 18 ([#363](https://github.com/googleapis/nodejs-promisify/issues/363))
+
+### Miscellaneous Chores
+
+* Upgrade to Node 18 ([#363](https://github.com/googleapis/nodejs-promisify/issues/363)) ([f8454e2](https://github.com/googleapis/nodejs-promisify/commit/f8454e21c87fd94f482e51675d604bf6f33cbeab))
+
+## [4.1.0](https://github.com/googleapis/nodejs-promisify/compare/v4.0.0...v4.1.0) (2025-03-05)
+
+
+### Features
+
+* Introduce Node 18 ([#360](https://github.com/googleapis/nodejs-promisify/issues/360)) ([a41ceac](https://github.com/googleapis/nodejs-promisify/commit/a41ceac378a8bda5d9cd054c9280153a8a1e3055))
+
+## [4.0.0](https://github.com/googleapis/nodejs-promisify/compare/v3.0.1...v4.0.0) (2023-08-08)
+
+
+### ⚠ BREAKING CHANGES
+
+* upgrade to Node 14 ([#325](https://github.com/googleapis/nodejs-promisify/issues/325))
+
+### Miscellaneous Chores
+
+* Upgrade to Node 14 ([#325](https://github.com/googleapis/nodejs-promisify/issues/325)) ([57d02c1](https://github.com/googleapis/nodejs-promisify/commit/57d02c1c23c65d63131bb99c07919ff80e5604cd))
+
+## [3.0.1](https://github.com/googleapis/nodejs-promisify/compare/v3.0.0...v3.0.1) (2022-08-23)
+
+
+### Bug Fixes
+
+* remove pip install statements ([#1546](https://github.com/googleapis/nodejs-promisify/issues/1546)) ([#310](https://github.com/googleapis/nodejs-promisify/issues/310)) ([c7c6883](https://github.com/googleapis/nodejs-promisify/commit/c7c688389de72ddc0181b19bceee2d95eacd3d96))
+
+## [3.0.0](https://github.com/googleapis/nodejs-promisify/compare/v2.0.4...v3.0.0) (2022-05-03)
+
+
+### ⚠ BREAKING CHANGES
+
+* drop node 10 from engines list, update typescript to 4.6.3 (#300)
+
+### Build System
+
+* drop node 10 from engines list, update typescript to 4.6.3 ([#300](https://github.com/googleapis/nodejs-promisify/issues/300)) ([fed2f14](https://github.com/googleapis/nodejs-promisify/commit/fed2f145a5256c939eb66b85a5c7c48332b8841d))
+
+### [2.0.4](https://www.github.com/googleapis/nodejs-promisify/compare/v2.0.3...v2.0.4) (2021-09-09)
+
+
+### Bug Fixes
+
+* **build:** switch primary branch to main ([#270](https://www.github.com/googleapis/nodejs-promisify/issues/270)) ([11242f7](https://www.github.com/googleapis/nodejs-promisify/commit/11242f7f76e170dae7a429f8d4064bf33be9bb3f))
+
+### [2.0.3](https://www.github.com/googleapis/nodejs-promisify/compare/v2.0.2...v2.0.3) (2020-09-04)
+
+
+### Bug Fixes
+
+* allow excluding accessor methods ([#228](https://www.github.com/googleapis/nodejs-promisify/issues/228)) ([114d8bc](https://www.github.com/googleapis/nodejs-promisify/commit/114d8bcef7093bdfda195a15e0c2f376195fd3fc))
+
+### [2.0.2](https://www.github.com/googleapis/nodejs-promisify/compare/v2.0.1...v2.0.2) (2020-07-06)
+
+
+### Bug Fixes
+
+* update node issue template ([#204](https://www.github.com/googleapis/nodejs-promisify/issues/204)) ([a2ba8d8](https://www.github.com/googleapis/nodejs-promisify/commit/a2ba8d8e45ef03d093d987292a467696745fc9fd))
+
+### [2.0.1](https://www.github.com/googleapis/nodejs-promisify/compare/v2.0.0...v2.0.1) (2020-05-08)
+
+
+### Bug Fixes
+
+* apache license URL ([#468](https://www.github.com/googleapis/nodejs-promisify/issues/468)) ([#191](https://www.github.com/googleapis/nodejs-promisify/issues/191)) ([0edc724](https://www.github.com/googleapis/nodejs-promisify/commit/0edc7246c53d25d9dd220b813561bcee97250783))
+
+## [2.0.0](https://www.github.com/googleapis/nodejs-promisify/compare/v1.0.4...v2.0.0) (2020-03-23)
+
+
+### ⚠ BREAKING CHANGES
+
+* update to latest version of gts/typescript (#183)
+* drop Node 8 from engines field (#184)
+
+### Features
+
+* drop Node 8 from engines field ([#184](https://www.github.com/googleapis/nodejs-promisify/issues/184)) ([7e6d3c5](https://www.github.com/googleapis/nodejs-promisify/commit/7e6d3c54066d89530ed25c7f9722efd252f43fb8))
+
+
+### Build System
+
+* update to latest version of gts/typescript ([#183](https://www.github.com/googleapis/nodejs-promisify/issues/183)) ([9c3ed12](https://www.github.com/googleapis/nodejs-promisify/commit/9c3ed12c12f4bb1e17af7440c6371c4cefddcd59))
+
+### [1.0.4](https://www.github.com/googleapis/nodejs-promisify/compare/v1.0.3...v1.0.4) (2019-12-05)
+
+
+### Bug Fixes
+
+* **deps:** pin TypeScript below 3.7.0 ([e48750e](https://www.github.com/googleapis/nodejs-promisify/commit/e48750ef96aa20eb3a2b73fe2f062d04430468a7))
+
+### [1.0.3](https://www.github.com/googleapis/nodejs-promisify/compare/v1.0.2...v1.0.3) (2019-11-13)
+
+
+### Bug Fixes
+
+* **docs:** add jsdoc-region-tag plugin ([#146](https://www.github.com/googleapis/nodejs-promisify/issues/146)) ([ff0ee74](https://www.github.com/googleapis/nodejs-promisify/commit/ff0ee7408f50e8f7147b8ccf7e10337aa5920076))
+
+### [1.0.2](https://www.github.com/googleapis/nodejs-promisify/compare/v1.0.1...v1.0.2) (2019-06-26)
+
+
+### Bug Fixes
+
+* **docs:** link to reference docs section on googleapis.dev ([#128](https://www.github.com/googleapis/nodejs-promisify/issues/128)) ([5a8bd90](https://www.github.com/googleapis/nodejs-promisify/commit/5a8bd90))
+
+### [1.0.1](https://www.github.com/googleapis/nodejs-promisify/compare/v1.0.0...v1.0.1) (2019-06-14)
+
+
+### Bug Fixes
+
+* **docs:** move to new client docs URL ([#124](https://www.github.com/googleapis/nodejs-promisify/issues/124)) ([34d18cd](https://www.github.com/googleapis/nodejs-promisify/commit/34d18cd))
+
+## [1.0.0](https://www.github.com/googleapis/nodejs-promisify/compare/v0.4.0...v1.0.0) (2019-05-02)
+
+
+### Build System
+
+* upgrade engines field to >=8.10.0 ([#108](https://www.github.com/googleapis/nodejs-promisify/issues/108)) ([78ab89c](https://www.github.com/googleapis/nodejs-promisify/commit/78ab89c))
+
+
+### BREAKING CHANGES
+
+* upgrade engines field to >=8.10.0 (#108)
+
+## v0.4.0
+
+02-12-2019 19:44 PST
+
+### New features
+- feat: add callbackify() and callbackifyAll() methods ([#82](https://github.com/googleapis/nodejs-promisify/pull/82))
+
+### Documentation
+- docs: update contributing path in README ([#86](https://github.com/googleapis/nodejs-promisify/pull/86))
+- chore: move CONTRIBUTING.md to root ([#85](https://github.com/googleapis/nodejs-promisify/pull/85))
+- docs: add lint/fix example to contributing guide ([#83](https://github.com/googleapis/nodejs-promisify/pull/83))
+
+### Internal / Testing Changes
+- build: create docs test npm scripts ([#88](https://github.com/googleapis/nodejs-promisify/pull/88))
+- build: test using @grpc/grpc-js in CI ([#87](https://github.com/googleapis/nodejs-promisify/pull/87))
+- build: ignore googleapis.com in doc link check ([#81](https://github.com/googleapis/nodejs-promisify/pull/81))
+- build: check broken links in generated docs ([#79](https://github.com/googleapis/nodejs-promisify/pull/79))
+- chore(deps): update dependency @types/sinon to v7 ([#78](https://github.com/googleapis/nodejs-promisify/pull/78))
+- chore(build): inject yoshi automation key ([#77](https://github.com/googleapis/nodejs-promisify/pull/77))
+- chore: update nyc and eslint configs ([#76](https://github.com/googleapis/nodejs-promisify/pull/76))
+- chore: fix publish.sh permission +x ([#74](https://github.com/googleapis/nodejs-promisify/pull/74))
+- fix(build): fix Kokoro release script ([#73](https://github.com/googleapis/nodejs-promisify/pull/73))
+- build: add Kokoro configs for autorelease ([#72](https://github.com/googleapis/nodejs-promisify/pull/72))
+- chore: always nyc report before calling codecov ([#69](https://github.com/googleapis/nodejs-promisify/pull/69))
+- chore: nyc ignore build/test by default ([#68](https://github.com/googleapis/nodejs-promisify/pull/68))
+- chore(build): update prettier config ([#66](https://github.com/googleapis/nodejs-promisify/pull/66))
+- fix: get the build passing ([#65](https://github.com/googleapis/nodejs-promisify/pull/65))
+- chore: update license file ([#64](https://github.com/googleapis/nodejs-promisify/pull/64))
+- fix(build): fix system key decryption ([#60](https://github.com/googleapis/nodejs-promisify/pull/60))
+- chore(deps): update dependency @types/sinon to v5.0.7 ([#58](https://github.com/googleapis/nodejs-promisify/pull/58))
+- fix: Pin @types/sinon to last compatible version ([#57](https://github.com/googleapis/nodejs-promisify/pull/57))
+- chore: add synth.metadata
+- chore(deps): update dependency gts to ^0.9.0 ([#54](https://github.com/googleapis/nodejs-promisify/pull/54))
+- chore: update eslintignore config ([#53](https://github.com/googleapis/nodejs-promisify/pull/53))
+- chore: use latest npm on Windows ([#52](https://github.com/googleapis/nodejs-promisify/pull/52))
+- chore: update CircleCI config ([#51](https://github.com/googleapis/nodejs-promisify/pull/51))
+- chore: include build in eslintignore ([#48](https://github.com/googleapis/nodejs-promisify/pull/48))
+- chore: update issue templates ([#44](https://github.com/googleapis/nodejs-promisify/pull/44))
+- chore: remove old issue template ([#42](https://github.com/googleapis/nodejs-promisify/pull/42))
+- build: run tests on node11 ([#41](https://github.com/googleapis/nodejs-promisify/pull/41))
+- chores(build): do not collect sponge.xml from windows builds ([#40](https://github.com/googleapis/nodejs-promisify/pull/40))
+- chores(build): run codecov on continuous builds ([#39](https://github.com/googleapis/nodejs-promisify/pull/39))
+- chore: update new issue template ([#38](https://github.com/googleapis/nodejs-promisify/pull/38))
+- chore(deps): update dependency sinon to v7 ([#33](https://github.com/googleapis/nodejs-promisify/pull/33))
+- build: fix codecov uploading on Kokoro ([#34](https://github.com/googleapis/nodejs-promisify/pull/34))
+- Update kokoro config ([#30](https://github.com/googleapis/nodejs-promisify/pull/30))
+- Update CI config ([#28](https://github.com/googleapis/nodejs-promisify/pull/28))
+- Don't publish sourcemaps ([#26](https://github.com/googleapis/nodejs-promisify/pull/26))
+- Update kokoro config ([#24](https://github.com/googleapis/nodejs-promisify/pull/24))
+- test: remove appveyor config ([#23](https://github.com/googleapis/nodejs-promisify/pull/23))
+- Update CI config ([#22](https://github.com/googleapis/nodejs-promisify/pull/22))
+- Enable prefer-const in the eslint config ([#21](https://github.com/googleapis/nodejs-promisify/pull/21))
+- Enable no-var in eslint ([#19](https://github.com/googleapis/nodejs-promisify/pull/19))
+- Update CI config ([#18](https://github.com/googleapis/nodejs-promisify/pull/18))
+
+## v0.3.1
+
+### Internal / Testing Changes
+- Add synth script and update CI (#14)
+- chore(deps): update dependency nyc to v13 (#12)
+- chore: ignore package-lock.json (#11)
+- chore(deps): lock file maintenance (#10)
+- chore: update renovate config (#9)
+- remove that whitespace (#8)
+- chore(deps): lock file maintenance (#7)
+- chore(deps): update dependency typescript to v3 (#6)
+- chore: assert.deelEqual => assert.deepStrictEqual (#5)
+- chore: move mocha options to mocha.opts (#4)
+- chore(deps): update dependency gts to ^0.8.0 (#1)
+- chore(deps): lock file maintenance (#3)
+- chore(deps): lock file maintenance (#2)
diff --git a/handwritten/nodejs-promisify/CODE_OF_CONDUCT.md b/handwritten/nodejs-promisify/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000000..2add2547a81
--- /dev/null
+++ b/handwritten/nodejs-promisify/CODE_OF_CONDUCT.md
@@ -0,0 +1,94 @@
+
+# Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of
+experience, education, socio-economic status, nationality, personal appearance,
+race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, or to ban temporarily or permanently any
+contributor for other behaviors that they deem inappropriate, threatening,
+offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+This Code of Conduct also applies outside the project spaces when the Project
+Steward has a reasonable belief that an individual's behavior may have a
+negative impact on the project or its community.
+
+## Conflict Resolution
+
+We do not believe that all conflict is bad; healthy debate and disagreement
+often yield positive results. However, it is never okay to be disrespectful or
+to engage in behavior that violates the project’s code of conduct.
+
+If you see someone violating the code of conduct, you are encouraged to address
+the behavior directly with those involved. Many issues can be resolved quickly
+and easily, and this gives people more control over the outcome of their
+dispute. If you are unable to resolve the matter for any reason, or if the
+behavior is threatening or harassing, report it. We are dedicated to providing
+an environment where participants feel welcome and safe.
+
+Reports should be directed to *googleapis-stewards@google.com*, the
+Project Steward(s) for *Google Cloud Client Libraries*. It is the Project Steward’s duty to
+receive and address reported violations of the code of conduct. They will then
+work with a committee consisting of representatives from the Open Source
+Programs Office and the Google Open Source Strategy team. If for any reason you
+are uncomfortable reaching out to the Project Steward, please email
+opensource@google.com.
+
+We will investigate every complaint, but you may not receive a direct response.
+We will use our discretion in determining when and how to follow up on reported
+incidents, which may range from not taking action to permanent expulsion from
+the project and project-sponsored spaces. We will notify the accused of the
+report and provide them an opportunity to discuss it before any action is taken.
+The identity of the reporter will be omitted from the details of the report
+supplied to the accused. In potentially harmful situations, such as ongoing
+harassment or threats to anyone's safety, we may take action without notice.
+
+## Attribution
+
+This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
+available at
+https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
\ No newline at end of file
diff --git a/handwritten/nodejs-promisify/CONTRIBUTING.md b/handwritten/nodejs-promisify/CONTRIBUTING.md
new file mode 100644
index 00000000000..72c44cada5e
--- /dev/null
+++ b/handwritten/nodejs-promisify/CONTRIBUTING.md
@@ -0,0 +1,74 @@
+# How to become a contributor and submit your own code
+
+**Table of contents**
+
+* [Contributor License Agreements](#contributor-license-agreements)
+* [Contributing a patch](#contributing-a-patch)
+* [Running the tests](#running-the-tests)
+* [Releasing the library](#releasing-the-library)
+
+## Contributor License Agreements
+
+We'd love to accept your sample apps and patches! Before we can take them, we
+have to jump a couple of legal hurdles.
+
+Please fill out either the individual or corporate Contributor License Agreement
+(CLA).
+
+ * If you are an individual writing original source code and you're sure you
+ own the intellectual property, then you'll need to sign an [individual CLA](https://developers.google.com/open-source/cla/individual).
+ * If you work for a company that wants to allow you to contribute your work,
+ then you'll need to sign a [corporate CLA](https://developers.google.com/open-source/cla/corporate).
+
+Follow either of the two links above to access the appropriate CLA and
+instructions for how to sign and return it. Once we receive it, we'll be able to
+accept your pull requests.
+
+## Contributing A Patch
+
+1. Submit an issue describing your proposed change to the repo in question.
+1. The repo owner will respond to your issue promptly.
+1. If your proposed change is accepted, and you haven't already done so, sign a
+ Contributor License Agreement (see details above).
+1. Fork the desired repo, develop and test your code changes.
+1. Ensure that your code adheres to the existing style in the code to which
+ you are contributing.
+1. Ensure that your code has an appropriate set of tests which all pass.
+1. Title your pull request following [Conventional Commits](https://www.conventionalcommits.org/) styling.
+1. Submit a pull request.
+
+### Before you begin
+
+1. [Select or create a Cloud Platform project][projects].
+1. [Set up authentication with a service account][auth] so you can access the
+ API from your local workstation.
+
+
+## Running the tests
+
+1. [Prepare your environment for Node.js setup][setup].
+
+1. Install dependencies:
+
+ npm install
+
+1. Run the tests:
+
+ # Run unit tests.
+ npm test
+
+ # Run sample integration tests.
+ npm run samples-test
+
+ # Run all system tests.
+ npm run system-test
+
+1. Lint (and maybe fix) any changes:
+
+ npm run fix
+
+[setup]: https://cloud.google.com/nodejs/docs/setup
+[projects]: https://console.cloud.google.com/project
+[billing]: https://support.google.com/cloud/answer/6293499#enable-billing
+
+[auth]: https://cloud.google.com/docs/authentication/getting-started
\ No newline at end of file
diff --git a/handwritten/nodejs-promisify/LICENSE b/handwritten/nodejs-promisify/LICENSE
new file mode 100644
index 00000000000..d6456956733
--- /dev/null
+++ b/handwritten/nodejs-promisify/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/handwritten/nodejs-promisify/README.md b/handwritten/nodejs-promisify/README.md
new file mode 100644
index 00000000000..73f418498ca
--- /dev/null
+++ b/handwritten/nodejs-promisify/README.md
@@ -0,0 +1,156 @@
+[//]: # "This README.md file is auto-generated, all changes to this file will be lost."
+[//]: # "To regenerate it, use `python -m synthtool`."
+
+
+# [Google Cloud Common Promisify: Node.js Client](https://github.com/googleapis/nodejs-promisify)
+
+[](https://cloud.google.com/terms/launch-stages)
+[](https://www.npmjs.org/package/@google-cloud/promisify)
+
+
+
+
+A simple utility for promisifying functions and classes.
+
+
+A comprehensive list of changes in each version may be found in
+[the CHANGELOG](https://github.com/googleapis/nodejs-promisify/blob/main/CHANGELOG.md).
+
+* [Google Cloud Common Promisify Node.js Client API Reference][client-docs]
+
+* [github.com/googleapis/nodejs-promisify](https://github.com/googleapis/nodejs-promisify)
+
+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)
+
+ * [Installing the client library](#installing-the-client-library)
+ * [Using the client library](#using-the-client-library)
+* [Samples](#samples)
+* [Versioning](#versioning)
+* [Contributing](#contributing)
+* [License](#license)
+
+## Quickstart
+
+### Installing the client library
+
+```bash
+npm install @google-cloud/promisify
+```
+
+
+### Using the client library
+
+```javascript
+const {promisify} = require('@google-cloud/promisify');
+
+/**
+ * This is a very basic example function that accepts a callback.
+ */
+function someCallbackFunction(name, callback) {
+ if (!name) {
+ callback(new Error('Name is required!'));
+ } else {
+ callback(null, `Well hello there, ${name}!`);
+ }
+}
+
+// let's promisify it!
+const somePromiseFunction = promisify(someCallbackFunction);
+
+async function quickstart() {
+ // now we can just `await` the function to use it like a promisified method
+ const [result] = await somePromiseFunction('nodestronaut');
+ console.log(result);
+}
+quickstart();
+
+```
+It's unlikely you will need to install this package directly, as it will be
+installed as a dependency when you install other `@google-cloud` packages.
+
+
+## Samples
+
+Samples are in the [`samples/`](https://github.com/googleapis/nodejs-promisify/tree/main/samples) directory. Each sample's `README.md` has instructions for running its sample.
+
+| Sample | Source Code | Try it |
+| --------------------------- | --------------------------------- | ------ |
+| Quickstart | [source code](https://github.com/googleapis/nodejs-promisify/blob/main/samples/quickstart.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-promisify&page=editor&open_in_editor=samples/quickstart.js,samples/README.md) |
+
+
+
+The [Google Cloud Common Promisify Node.js Client API Reference][client-docs] documentation
+also contains 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 @google-cloud/promisify@legacy-8` installs client libraries
+for versions compatible with Node.js 8.
+
+## Versioning
+
+This library follows [Semantic Versioning](http://semver.org/).
+
+
+
+This library is considered to be **stable**. The code surface will not change in backwards-incompatible ways
+unless absolutely necessary (e.g. because of critical security issues) or with
+an extensive deprecation period. Issues and requests against **stable** libraries
+are addressed with the highest priority.
+
+
+
+
+
+
+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/nodejs-promisify/blob/main/CONTRIBUTING.md).
+
+Please note that this `README.md`, the `samples/README.md`,
+and a variety of configuration files in this repository (including `.nycrc` and `tsconfig.json`)
+are generated from a central template. To edit one of these files, make an edit
+to its templates in
+[directory](https://github.com/googleapis/synthtool).
+
+## License
+
+Apache Version 2.0
+
+See [LICENSE](https://github.com/googleapis/nodejs-promisify/blob/main/LICENSE)
+
+[client-docs]: https://googleapis.dev/nodejs/promisify/latest
+
+[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
+
+[auth]: https://cloud.google.com/docs/authentication/external/set-up-adc-local
diff --git a/handwritten/nodejs-promisify/linkinator.config.json b/handwritten/nodejs-promisify/linkinator.config.json
new file mode 100644
index 00000000000..da66523a6d0
--- /dev/null
+++ b/handwritten/nodejs-promisify/linkinator.config.json
@@ -0,0 +1,11 @@
+{
+ "recurse": true,
+ "skip": [
+ "https://codecov.io/gh/googleapis/",
+ "www.googleapis.com",
+ "img.shields.io",
+ "docs/js/menu-wc_es5.js"
+ ],
+ "silent": true,
+ "concurrency": 10
+}
diff --git a/handwritten/nodejs-promisify/owlbot.py b/handwritten/nodejs-promisify/owlbot.py
new file mode 100644
index 00000000000..46c99b19b9a
--- /dev/null
+++ b/handwritten/nodejs-promisify/owlbot.py
@@ -0,0 +1,20 @@
+# Copyright 2024 Google LLC. All Rights Reserved.
+#
+# 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.
+
+import synthtool as s
+import synthtool.gcp as gcp
+
+common_templates = gcp.CommonTemplates()
+templates = common_templates.node_library()
+s.copy(sources=templates, excludes=["LICENSE", "README.md", ".github/ISSUE_TEMPLATE", ".github/scripts", ".kokoro", ".github/workflows/issues-no-repro.yaml", ".jsdoc.js"])
diff --git a/handwritten/nodejs-promisify/package.json b/handwritten/nodejs-promisify/package.json
new file mode 100644
index 00000000000..12b120dd56f
--- /dev/null
+++ b/handwritten/nodejs-promisify/package.json
@@ -0,0 +1,57 @@
+{
+ "name": "@google-cloud/promisify",
+ "version": "5.0.0",
+ "description": "A simple utility for promisifying functions and classes.",
+ "main": "build/src/index.js",
+ "types": "build/src/index.d.ts",
+ "repository": {
+ "type": "git",
+ "directory": "handwritten/nodejs-promisify",
+ "url": "https://github.com/googleapis/google-cloud-node.git"
+ },
+ "scripts": {
+ "test": "c8 mocha build/test",
+ "lint": "gts check",
+ "compile": "tsc -p .",
+ "fix": "gts fix",
+ "prepare": "npm run compile",
+ "pretest": "npm run compile",
+ "docs": "jsdoc -c .jsdoc.js",
+ "presystem-test": "npm run compile",
+ "samples-test": "cd samples/ && npm link ../ && npm test && cd ../",
+ "system-test": "mocha build/system-test",
+ "docs-test": "linkinator docs",
+ "predocs-test": "npm run docs",
+ "prelint": "cd samples; npm link ../; npm install",
+ "clean": "gts clean",
+ "precompile": "gts clean"
+ },
+ "keywords": [],
+ "files": [
+ "build/src",
+ "!build/src/**/*.map"
+ ],
+ "author": "Google Inc.",
+ "license": "Apache-2.0",
+ "devDependencies": {
+ "@types/mocha": "^10.0.10",
+ "@types/node": "^22.13.9",
+ "@types/sinon": "^17.0.4",
+ "c8": "^10.1.3",
+ "chai": "^5.2.0",
+ "codecov": "^3.8.3",
+ "gts": "^6.0.2",
+ "hard-rejection": "^2.1.0",
+ "jsdoc": "^4.0.4",
+ "jsdoc-fresh": "^3.0.0",
+ "jsdoc-region-tag": "^3.0.0",
+ "linkinator": "^6.1.2",
+ "mocha": "^11.1.0",
+ "sinon": "^19.0.2",
+ "typescript": "^5.8.2"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/handwritten/nodejs-promisify"
+}
diff --git a/handwritten/nodejs-promisify/samples/.eslintrc.yml b/handwritten/nodejs-promisify/samples/.eslintrc.yml
new file mode 100644
index 00000000000..282535f55f6
--- /dev/null
+++ b/handwritten/nodejs-promisify/samples/.eslintrc.yml
@@ -0,0 +1,3 @@
+---
+rules:
+ no-console: off
diff --git a/handwritten/nodejs-promisify/samples/README.md b/handwritten/nodejs-promisify/samples/README.md
new file mode 100644
index 00000000000..2d7984dab1e
--- /dev/null
+++ b/handwritten/nodejs-promisify/samples/README.md
@@ -0,0 +1,50 @@
+[//]: # "This README.md file is auto-generated, all changes to this file will be lost."
+[//]: # "To regenerate it, use `python -m synthtool`."
+
+
+# [Google Cloud Common Promisify: Node.js Samples](https://github.com/googleapis/nodejs-promisify)
+
+[![Open in Cloud Shell][shell_img]][shell_link]
+
+
+
+## Table of Contents
+
+* [Before you begin](#before-you-begin)
+* [Samples](#samples)
+ * [Quickstart](#quickstart)
+
+## Before you begin
+
+Before running the samples, make sure you've followed the steps outlined in
+[Using the client library](https://github.com/googleapis/nodejs-promisify#using-the-client-library).
+
+`cd samples`
+
+`npm install`
+
+`cd ..`
+
+## Samples
+
+
+
+### Quickstart
+
+View the [source code](https://github.com/googleapis/nodejs-promisify/blob/main/samples/quickstart.js).
+
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-promisify&page=editor&open_in_editor=samples/quickstart.js,samples/README.md)
+
+__Usage:__
+
+
+`node samples/quickstart.js`
+
+
+
+
+
+
+[shell_img]: https://gstatic.com/cloudssh/images/open-btn.png
+[shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-promisify&page=editor&open_in_editor=samples/README.md
+[product-docs]:
diff --git a/handwritten/nodejs-promisify/samples/package.json b/handwritten/nodejs-promisify/samples/package.json
new file mode 100644
index 00000000000..f4f614ee576
--- /dev/null
+++ b/handwritten/nodejs-promisify/samples/package.json
@@ -0,0 +1,24 @@
+{
+ "description": "Samples for the nodejs-promisify npm module.",
+ "license": "Apache-2.0",
+ "author": "Google LLC",
+ "engines": {
+ "node": ">=18"
+ },
+ "files": [
+ "*.js",
+ "!test/"
+ ],
+ "repository": "googleapis/nodejs-promisify",
+ "private": true,
+ "scripts": {
+ "test": "mocha"
+ },
+ "dependencies": {
+ "@google-cloud/promisify": "^5.0.0"
+ },
+ "devDependencies": {
+ "chai": "^4.2.0",
+ "mocha": "^8.0.0"
+ }
+}
\ No newline at end of file
diff --git a/handwritten/nodejs-promisify/samples/quickstart.js b/handwritten/nodejs-promisify/samples/quickstart.js
new file mode 100644
index 00000000000..2101750e425
--- /dev/null
+++ b/handwritten/nodejs-promisify/samples/quickstart.js
@@ -0,0 +1,38 @@
+// Copyright 2018 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.
+
+// [START promisify_quickstart]
+const {promisify} = require('@google-cloud/promisify');
+
+/**
+ * This is a very basic example function that accepts a callback.
+ */
+function someCallbackFunction(name, callback) {
+ if (!name) {
+ callback(new Error('Name is required!'));
+ } else {
+ callback(null, `Well hello there, ${name}!`);
+ }
+}
+
+// let's promisify it!
+const somePromiseFunction = promisify(someCallbackFunction);
+
+async function quickstart() {
+ // now we can just `await` the function to use it like a promisified method
+ const [result] = await somePromiseFunction('nodestronaut');
+ console.log(result);
+}
+quickstart();
+// [END promisify_quickstart]
diff --git a/handwritten/nodejs-promisify/samples/test/test.js b/handwritten/nodejs-promisify/samples/test/test.js
new file mode 100644
index 00000000000..5851c9f5e7c
--- /dev/null
+++ b/handwritten/nodejs-promisify/samples/test/test.js
@@ -0,0 +1,26 @@
+// Copyright 2018 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.
+
+const {assert} = require('chai');
+const {describe, it} = require('mocha');
+const cp = require('child_process');
+
+const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'});
+
+describe('quickstart samples', () => {
+ it('should run the quickstart', async () => {
+ const stdout = execSync('node quickstart.js');
+ assert.include(stdout, 'Well hello there, nodestronaut!');
+ });
+});
diff --git a/handwritten/nodejs-promisify/src/index.ts b/handwritten/nodejs-promisify/src/index.ts
new file mode 100644
index 00000000000..a7cb9e3b67a
--- /dev/null
+++ b/handwritten/nodejs-promisify/src/index.ts
@@ -0,0 +1,219 @@
+/* eslint-disable prefer-rest-params */
+
+// Copyright 2014 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.
+
+export interface PromisifyAllOptions extends PromisifyOptions {
+ /**
+ * Array of methods to ignore when promisifying.
+ */
+ exclude?: string[];
+}
+
+export interface PromisifyOptions {
+ /**
+ * Resolve the promise with single arg instead of an array.
+ */
+ singular?: boolean;
+}
+
+export interface PromiseMethod extends Function {
+ promisified_?: boolean;
+}
+
+export interface WithPromise {
+ Promise?: PromiseConstructor;
+}
+
+export interface CallbackifyAllOptions {
+ /**
+ * Array of methods to ignore when callbackifying.
+ */
+ exclude?: string[];
+}
+
+export interface CallbackMethod extends Function {
+ callbackified_?: boolean;
+}
+
+/**
+ * Wraps a callback style function to conditionally return a promise.
+ *
+ * @param {function} originalMethod - The method to promisify.
+ * @param {object=} options - Promise options.
+ * @param {boolean} options.singular - Resolve the promise with single arg instead of an array.
+ * @return {function} wrapped
+ */
+export function promisify(
+ originalMethod: PromiseMethod,
+ options?: PromisifyOptions,
+) {
+ if (originalMethod.promisified_) {
+ return originalMethod;
+ }
+
+ options = options || {};
+
+ const slice = Array.prototype.slice;
+
+ // tslint:disable-next-line:no-any
+ const wrapper: any = function (this: WithPromise) {
+ let last;
+
+ for (last = arguments.length - 1; last >= 0; last--) {
+ const arg = arguments[last];
+
+ if (typeof arg === 'undefined') {
+ continue; // skip trailing undefined.
+ }
+
+ if (typeof arg !== 'function') {
+ break; // non-callback last argument found.
+ }
+
+ return originalMethod.apply(this, arguments);
+ }
+
+ // peel trailing undefined.
+ const args = slice.call(arguments, 0, last + 1);
+
+ // tslint:disable-next-line:variable-name
+ let PromiseCtor = Promise;
+
+ // Because dedupe will likely create a single install of
+ // @google-cloud/common to be shared amongst all modules, we need to
+ // localize it at the Service level.
+ if (this && this.Promise) {
+ PromiseCtor = this.Promise;
+ }
+
+ return new PromiseCtor((resolve, reject) => {
+ // tslint:disable-next-line:no-any
+ args.push((...args: any[]) => {
+ const callbackArgs = slice.call(args);
+ const err = callbackArgs.shift();
+
+ if (err) {
+ return reject(err);
+ }
+
+ if (options!.singular && callbackArgs.length === 1) {
+ resolve(callbackArgs[0]);
+ } else {
+ resolve(callbackArgs);
+ }
+ });
+
+ originalMethod.apply(this, args);
+ });
+ };
+
+ wrapper.promisified_ = true;
+ return wrapper;
+}
+
+/**
+ * Promisifies certain Class methods. This will not promisify private or
+ * streaming methods.
+ *
+ * @param {module:common/service} Class - Service class.
+ * @param {object=} options - Configuration object.
+ */
+// tslint:disable-next-line:variable-name
+export function promisifyAll(Class: Function, options?: PromisifyAllOptions) {
+ const exclude = (options && options.exclude) || [];
+ const ownPropertyNames = Object.getOwnPropertyNames(Class.prototype);
+ const methods = ownPropertyNames.filter(methodName => {
+ // clang-format off
+ return (
+ !exclude.includes(methodName) &&
+ typeof Class.prototype[methodName] === 'function' && // is it a function?
+ !/(^_|(Stream|_)|promise$)|^constructor$/.test(methodName) // is it promisable?
+ );
+ // clang-format on
+ });
+
+ methods.forEach(methodName => {
+ const originalMethod = Class.prototype[methodName];
+ if (!originalMethod.promisified_) {
+ Class.prototype[methodName] = exports.promisify(originalMethod, options);
+ }
+ });
+}
+
+/**
+ * Wraps a promisy type function to conditionally call a callback function.
+ *
+ * @param {function} originalMethod - The method to callbackify.
+ * @param {object=} options - Callback options.
+ * @param {boolean} options.singular - Pass to the callback a single arg instead of an array.
+ * @return {function} wrapped
+ */
+export function callbackify(originalMethod: CallbackMethod) {
+ if (originalMethod.callbackified_) {
+ return originalMethod;
+ }
+
+ // tslint:disable-next-line:no-any
+ const wrapper = function (this: any) {
+ if (typeof arguments[arguments.length - 1] !== 'function') {
+ return originalMethod.apply(this, arguments);
+ }
+
+ const cb = Array.prototype.pop.call(arguments);
+
+ originalMethod.apply(this, arguments).then(
+ // tslint:disable-next-line:no-any
+ (res: any) => {
+ res = Array.isArray(res) ? res : [res];
+ cb(null, ...res);
+ },
+ (err: Error) => cb(err),
+ );
+ };
+ wrapper.callbackified_ = true;
+ return wrapper;
+}
+
+/**
+ * Callbackifies certain Class methods. This will not callbackify private or
+ * streaming methods.
+ *
+ * @param {module:common/service} Class - Service class.
+ * @param {object=} options - Configuration object.
+ */
+export function callbackifyAll(
+ // tslint:disable-next-line:variable-name
+ Class: Function,
+ options?: CallbackifyAllOptions,
+) {
+ const exclude = (options && options.exclude) || [];
+ const ownPropertyNames = Object.getOwnPropertyNames(Class.prototype);
+ const methods = ownPropertyNames.filter(methodName => {
+ // clang-format off
+ return (
+ !exclude.includes(methodName) &&
+ typeof Class.prototype[methodName] === 'function' && // is it a function?
+ !/^_|(Stream|_)|^constructor$/.test(methodName) // is it callbackifyable?
+ );
+ // clang-format on
+ });
+
+ methods.forEach(methodName => {
+ const originalMethod = Class.prototype[methodName];
+ if (!originalMethod.callbackified_) {
+ Class.prototype[methodName] = exports.callbackify(originalMethod);
+ }
+ });
+}
diff --git a/handwritten/nodejs-promisify/system-test/system.ts b/handwritten/nodejs-promisify/system-test/system.ts
new file mode 100644
index 00000000000..05638eda311
--- /dev/null
+++ b/handwritten/nodejs-promisify/system-test/system.ts
@@ -0,0 +1,15 @@
+// Copyright 2018 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.
+
+console.warn('no system tests available 👻');
diff --git a/handwritten/nodejs-promisify/test/index.ts b/handwritten/nodejs-promisify/test/index.ts
new file mode 100644
index 00000000000..78808466a86
--- /dev/null
+++ b/handwritten/nodejs-promisify/test/index.ts
@@ -0,0 +1,413 @@
+// Copyright 2014 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 @typescript-eslint/no-empty-function,prefer-rest-params */
+
+import * as assert from 'assert';
+import {describe, it, afterEach, beforeEach} from 'mocha';
+import * as sinon from 'sinon';
+import * as util from '../src';
+
+const noop = () => {};
+const sandbox = sinon.createSandbox();
+
+describe('promisifyAll', () => {
+ const fakeArgs = [null, 1, 2, 3];
+ const fakeError = new Error('err.');
+
+ let FakeClass: any;
+
+ beforeEach(() => {
+ FakeClass = class {
+ methodName(callback: Function) {
+ callback(...fakeArgs);
+ }
+ methodSingle(callback: Function) {
+ callback(null, fakeArgs[1]);
+ }
+ methodError(callback: Function) {
+ callback(fakeError);
+ }
+ };
+ FakeClass.prototype.method_ = noop;
+ FakeClass.prototype._method = noop;
+ FakeClass.prototype.methodStream = noop;
+ FakeClass.prototype.promise = noop;
+
+ util.promisifyAll(FakeClass);
+ const fc = new FakeClass();
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should promisify the correct method', () => {
+ assert(FakeClass.prototype.methodName.promisified_);
+ assert(FakeClass.prototype.methodSingle.promisified_);
+ assert(FakeClass.prototype.methodError.promisified_);
+
+ assert.strictEqual(FakeClass.prototype.method_, noop);
+ assert.strictEqual(FakeClass.prototype._method, noop);
+ assert.strictEqual(FakeClass.prototype.methodStream, noop);
+ assert.strictEqual(FakeClass.prototype.promise, noop);
+ });
+
+ // The ts compiler will convert a class to the current node version target,
+ // in this case v4, which means that using the class keyword to create a
+ // class won't actually test that this method works on ES classes. Using
+ // eval works around that compilation. The class syntax is a syntax error
+ // in node v4 which is why the eval call is wrapped in a try catch block.
+ try {
+ eval(`
+ const assert2 = require('assert');
+ const util = require('../src');
+ it('should work on ES classes', () => {
+ class MyESClass {
+ myMethod(str, callback) {
+ callback(str.toUpperCase());
+ }
+ }
+ util.promisifyAll(MyESClass);
+ assert2(MyESClass.prototype.myMethod.promisified_);
+ });
+ `);
+ } catch (error) {
+ it.skip('should work on ES classes');
+ }
+
+ it('should optionally accept an exclude list', () => {
+ function FakeClass2() {}
+ FakeClass2.prototype.methodSync = noop;
+ FakeClass2.prototype.method = () => {};
+ util.promisifyAll(FakeClass2, {
+ exclude: ['methodSync'],
+ });
+ assert.strictEqual(FakeClass2.prototype.methodSync, noop);
+ assert(FakeClass2.prototype.method.promisified_);
+ });
+
+ it('should honor excluded properties first', done => {
+ function FakeClass2() {}
+ Object.defineProperty(FakeClass2.prototype, 'method', {
+ get: () => {
+ done(new Error('Accessor method should not be called.'));
+ return {};
+ },
+ });
+ assert.doesNotThrow(() => {
+ util.promisifyAll(FakeClass2, {
+ exclude: ['method'],
+ });
+ done();
+ });
+ });
+
+ it('should pass the options object to promisify', done => {
+ const fakeOptions = {
+ a: 'a',
+ } as util.PromisifyAllOptions;
+
+ const stub = sandbox
+ .stub(util, 'promisify')
+ .callsFake((method, options) => {
+ assert.strictEqual(method, FakeClass2.prototype.method);
+ assert.strictEqual(options, fakeOptions);
+ done();
+ stub.restore();
+ });
+
+ function FakeClass2() {}
+ FakeClass2.prototype.method = () => {};
+ util.promisifyAll(FakeClass2, fakeOptions);
+ });
+
+ it('should not re-promisify methods', () => {
+ const method = FakeClass.prototype.methodName;
+ util.promisifyAll(FakeClass);
+ assert.strictEqual(FakeClass.prototype.methodName, method);
+ });
+});
+
+describe('promisify', () => {
+ const fakeContext = {};
+ let func: Function;
+ let fakeArgs: Array;
+
+ beforeEach(() => {
+ fakeArgs = [null, 1, 2, 3];
+ func = util.promisify(function (this: {}, callback: () => void) {
+ (callback as any).apply(this, fakeArgs);
+ });
+ });
+
+ it('should not re-promisify the function', () => {
+ const original = func;
+ func = util.promisify(func);
+ assert.strictEqual(original, func);
+ });
+
+ it('should not return a promise in callback mode', done => {
+ let returnVal: any;
+ returnVal = func.call(fakeContext, function (this: {}) {
+ const args = [...arguments];
+ assert.deepStrictEqual(args, fakeArgs);
+ assert.strictEqual(this, fakeContext);
+ assert(!returnVal);
+ returnVal = null; // this is to suppress prefer-const.
+ done();
+ });
+ });
+
+ it('should return a promise when the callback is omitted', () => {
+ return func().then((args: Array<{}>) => {
+ assert.deepStrictEqual(args, fakeArgs.slice(1));
+ });
+ });
+
+ it('should reject the promise on a failed request', () => {
+ const error = new Error('err');
+ fakeArgs = [error];
+ return func().then(
+ () => {
+ throw new Error('Should have gone to failure block');
+ },
+ (err: Error) => {
+ assert.strictEqual(err, error);
+ },
+ );
+ });
+
+ it('should allow the Promise object to be overridden', () => {
+ const FakePromise = class {};
+ const promise = func.call({Promise: FakePromise});
+ assert(promise instanceof FakePromise);
+ });
+
+ it('should resolve singular arguments', () => {
+ const fakeArg = 'hi';
+
+ func = util.promisify(
+ (callback: () => void) => {
+ (callback as any).apply(func, [null, fakeArg]);
+ },
+ {
+ singular: true,
+ },
+ );
+
+ return func().then((arg: {}) => {
+ assert.strictEqual(arg, fakeArg);
+ });
+ });
+
+ it('should ignore singular when multiple args are present', () => {
+ const fakeArgs: any[] = ['a', 'b'];
+
+ func = util.promisify(
+ (callback: Function) => {
+ callback.apply(func, [null].concat(fakeArgs));
+ },
+ {
+ singular: true,
+ },
+ );
+
+ return func().then((args: Array<{}>) => {
+ assert.deepStrictEqual(args, fakeArgs);
+ });
+ });
+
+ describe('trailing undefined arguments', () => {
+ it('should not return a promise in callback mode', () => {
+ const func = util.promisify((optional: Function) => {
+ assert.strictEqual(typeof optional, 'function');
+ optional(null);
+ });
+
+ const returnVal = func(() => {});
+ assert.strictEqual(returnVal, undefined);
+ });
+
+ it('should return a promise when callback omitted', done => {
+ const func = util.promisify((optional: Function, ...args: Array<{}>) => {
+ assert.strictEqual(args.length, 0);
+ assert.strictEqual(typeof optional, 'function');
+ optional(null);
+ });
+
+ func(undefined, undefined).then(() => {
+ done();
+ });
+ });
+
+ it('should not mistake non-function args for callbacks', done => {
+ const func = util.promisify(
+ (foo: {}, optional: Function, ...args: Array<{}>) => {
+ assert.strictEqual(args.length, 0);
+ assert.strictEqual(typeof optional, 'function');
+ optional(null);
+ },
+ );
+
+ func('foo').then(() => {
+ done();
+ });
+ });
+ });
+});
+
+describe('callbackifyAll', () => {
+ const fakeArgs = [1, 2, 3];
+ const fakeError = new Error('err.');
+
+ let FakeClass: any;
+
+ beforeEach(() => {
+ FakeClass = class {
+ async methodName() {
+ return fakeArgs;
+ }
+ async methodError() {
+ throw fakeError;
+ }
+ };
+ FakeClass.prototype.method_ = noop;
+ FakeClass.prototype._method = noop;
+ FakeClass.prototype.methodStream = noop;
+
+ util.callbackifyAll(FakeClass);
+ });
+
+ it('should callbackify the correct method', () => {
+ assert(FakeClass.prototype.methodName.callbackified_);
+ assert(FakeClass.prototype.methodError.callbackified_);
+
+ assert.strictEqual(FakeClass.prototype.method_, noop);
+ assert.strictEqual(FakeClass.prototype._method, noop);
+ assert.strictEqual(FakeClass.prototype.methodStream, noop);
+ });
+
+ it('should optionally accept an exclude list', () => {
+ function FakeClass2() {}
+ FakeClass2.prototype.methodSync = noop;
+ FakeClass2.prototype.method = () => {};
+ util.callbackifyAll(FakeClass2, {
+ exclude: ['methodSync'],
+ });
+ assert.strictEqual(FakeClass2.prototype.methodSync, noop);
+ assert(FakeClass2.prototype.method.callbackified_);
+ assert.strictEqual(FakeClass2.prototype.methodSync, noop);
+ });
+
+ it('should honor excluded properties first', done => {
+ function FakeClass2() {}
+ Object.defineProperty(FakeClass2.prototype, 'method', {
+ get: () => {
+ done(new Error('Accessor method should not be called.'));
+ return {};
+ },
+ });
+ assert.doesNotThrow(() => {
+ util.callbackifyAll(FakeClass2, {
+ exclude: ['method'],
+ });
+ done();
+ });
+ });
+
+ it('should not re-callbackify method', () => {
+ const method = FakeClass.prototype.methodName;
+ util.callbackifyAll(FakeClass);
+ assert.strictEqual(FakeClass.prototype.methodName, method);
+ });
+});
+
+describe('callbackify', () => {
+ let func: Function;
+ let fakeArgs: number[];
+
+ beforeEach(() => {
+ fakeArgs = [1, 2, 3];
+
+ func = util.callbackify(async (_this: {}) => {
+ return fakeArgs;
+ });
+ });
+
+ it('should not re-callbackify the function', () => {
+ const original = func;
+ func = util.callbackify(func);
+ assert.strictEqual(original, func);
+ });
+
+ it('should return a promise when callback is not provided', () => {
+ func().then((args: []) => {
+ assert.deepStrictEqual(args, fakeArgs);
+ });
+ });
+
+ it('should call the callback if it is provided', done => {
+ func(function (this: {}) {
+ const args = [].slice.call(arguments);
+ assert.deepStrictEqual(args, [null, ...fakeArgs]);
+ done();
+ });
+ });
+
+ it('should call the provided callback with undefined', done => {
+ func = util.callbackify(async (_this: {}) => {});
+ func((err: Error, resp: {}) => {
+ assert.strictEqual(err, null);
+ assert.strictEqual(resp, undefined);
+ done();
+ });
+ });
+
+ it('should call the provided callback with null', done => {
+ func = util.callbackify(async (_this: {}) => {
+ return null;
+ });
+ func(function (this: {}) {
+ const args = [].slice.call(arguments);
+ assert.deepStrictEqual(args, [null, null]);
+ done();
+ });
+ });
+
+ it('should call the callback with error when promise rejects', () => {
+ const error = new Error('err');
+ func = util.callbackify(async () => {
+ throw error;
+ });
+ func((err: Error) => assert.strictEqual(err, error));
+ });
+
+ it('should call the callback only a single time when the promise resolves but callback throws an error', () => {
+ const error = new Error('err');
+ const callback = sinon.stub().throws(error);
+ const originalRejection = process.listeners('unhandledRejection').pop();
+ if (originalRejection) {
+ process.removeListener('unhandledRejection', originalRejection!);
+ }
+ process.once('unhandledRejection', err => {
+ assert.strictEqual(error, err);
+ assert.ok(callback.calledOnce);
+ if (originalRejection) {
+ process.listeners('unhandledRejection').push(originalRejection!);
+ }
+ });
+ func(callback);
+ });
+});
diff --git a/handwritten/nodejs-promisify/tsconfig.json b/handwritten/nodejs-promisify/tsconfig.json
new file mode 100644
index 00000000000..8b14ad98550
--- /dev/null
+++ b/handwritten/nodejs-promisify/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "extends": "./node_modules/gts/tsconfig-google.json",
+ "compilerOptions": {
+ "lib": ["es2018", "dom"],
+ "rootDir": ".",
+ "outDir": "build"
+ },
+ "include": [
+ "src/*.ts",
+ "test/*.ts",
+ "system-test/*.ts"
+ ]
+}
diff --git a/release-please-config.json b/release-please-config.json
index 9c211610789..67149669af3 100644
--- a/release-please-config.json
+++ b/release-please-config.json
@@ -1,6 +1,8 @@
{
+ "bump-minor-pre-major": true,
"initial-version": "0.1.0",
"packages": {
+ "handwritten/nodejs-promisify": {},
"packages/gapic-node-processing": {},
"packages/google-ads-admanager": {},
"packages/google-ads-datamanager": {},
@@ -149,11 +151,11 @@
"packages/google-cloud-saasplatform-saasservicemgmt": {},
"packages/google-cloud-scheduler": {},
"packages/google-cloud-secretmanager": {},
+ "packages/google-cloud-securesourcemanager": {},
"packages/google-cloud-security-privateca": {},
"packages/google-cloud-security-publicca": {},
"packages/google-cloud-securitycenter": {},
"packages/google-cloud-securitycentermanagement": {},
- "packages/google-cloud-securesourcemanager": {},
"packages/google-cloud-servicedirectory": {},
"packages/google-cloud-servicehealth": {},
"packages/google-cloud-shell": {},
@@ -227,6 +229,5 @@
"type": "sentence-case"
}
],
- "bump-minor-pre-major": true,
"release-type": "node"
}
\ No newline at end of file