@hasna/connectors 1.1.5 → 1.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.js +21 -1
- package/bin/mcp.js +31 -2
- package/bin/serve.js +20 -0
- package/connectors/connect-gmail/src/api/attachments.ts +152 -0
- package/connectors/connect-gmail/src/api/bulk.ts +748 -0
- package/connectors/connect-gmail/src/api/client.ts +131 -0
- package/connectors/connect-gmail/src/api/drafts.ts +198 -0
- package/connectors/connect-gmail/src/api/export.ts +312 -0
- package/connectors/connect-gmail/src/api/filters.ts +127 -0
- package/connectors/connect-gmail/src/api/index.ts +63 -0
- package/connectors/connect-gmail/src/api/labels.ts +123 -0
- package/connectors/connect-gmail/src/api/messages.ts +527 -0
- package/connectors/connect-gmail/src/api/profile.ts +72 -0
- package/connectors/connect-gmail/src/api/threads.ts +85 -0
- package/connectors/connect-gmail/src/cli/index.ts +2447 -0
- package/connectors/connect-gmail/src/index.ts +30 -0
- package/connectors/connect-gmail/src/types/index.ts +202 -0
- package/connectors/connect-gmail/src/utils/auth.ts +256 -0
- package/connectors/connect-gmail/src/utils/config.ts +466 -0
- package/connectors/connect-gmail/src/utils/contacts.ts +147 -0
- package/connectors/connect-gmail/src/utils/markdown.ts +119 -0
- package/connectors/connect-gmail/src/utils/output.ts +119 -0
- package/connectors/connect-gmail/src/utils/settings.ts +87 -0
- package/connectors/connect-gmail/tsconfig.json +16 -0
- package/connectors/connect-googledrive/src/cli/index.ts +71 -7
- package/connectors/connect-mercury/CLAUDE.md +1 -0
- package/connectors/connect-mercury/src/cli/index.ts +213 -17
- package/connectors/connect-telegram/src/api/bot.ts +223 -0
- package/connectors/connect-telegram/src/api/chats.ts +290 -0
- package/connectors/connect-telegram/src/api/client.ts +134 -0
- package/connectors/connect-telegram/src/api/index.ts +66 -0
- package/connectors/connect-telegram/src/api/inline.ts +63 -0
- package/connectors/connect-telegram/src/api/messages.ts +781 -0
- package/connectors/connect-telegram/src/api/updates.ts +97 -0
- package/connectors/connect-telegram/src/cli/index.ts +690 -0
- package/connectors/connect-telegram/src/index.ts +22 -0
- package/connectors/connect-telegram/src/types/index.ts +617 -0
- package/connectors/connect-telegram/src/utils/config.ts +197 -0
- package/connectors/connect-telegram/src/utils/output.ts +119 -0
- package/connectors/connect-telegram/tsconfig.json +16 -0
- package/connectors/connect-yousign/CLAUDE.md +48 -0
- package/connectors/connect-yousign/bun.lock +32 -0
- package/connectors/connect-yousign/node_modules/@types/bun/LICENSE +21 -0
- package/connectors/connect-yousign/node_modules/@types/bun/README.md +20 -0
- package/connectors/connect-yousign/node_modules/@types/bun/index.d.ts +1 -0
- package/connectors/connect-yousign/node_modules/@types/bun/package.json +53 -0
- package/connectors/connect-yousign/node_modules/@types/node/LICENSE +21 -0
- package/connectors/connect-yousign/node_modules/@types/node/README.md +15 -0
- package/connectors/connect-yousign/node_modules/@types/node/assert/strict.d.ts +105 -0
- package/connectors/connect-yousign/node_modules/@types/node/assert.d.ts +955 -0
- package/connectors/connect-yousign/node_modules/@types/node/async_hooks.d.ts +623 -0
- package/connectors/connect-yousign/node_modules/@types/node/buffer.buffer.d.ts +466 -0
- package/connectors/connect-yousign/node_modules/@types/node/buffer.d.ts +1810 -0
- package/connectors/connect-yousign/node_modules/@types/node/child_process.d.ts +1433 -0
- package/connectors/connect-yousign/node_modules/@types/node/cluster.d.ts +486 -0
- package/connectors/connect-yousign/node_modules/@types/node/compatibility/iterators.d.ts +21 -0
- package/connectors/connect-yousign/node_modules/@types/node/console.d.ts +151 -0
- package/connectors/connect-yousign/node_modules/@types/node/constants.d.ts +20 -0
- package/connectors/connect-yousign/node_modules/@types/node/crypto.d.ts +4065 -0
- package/connectors/connect-yousign/node_modules/@types/node/dgram.d.ts +564 -0
- package/connectors/connect-yousign/node_modules/@types/node/diagnostics_channel.d.ts +576 -0
- package/connectors/connect-yousign/node_modules/@types/node/dns/promises.d.ts +503 -0
- package/connectors/connect-yousign/node_modules/@types/node/dns.d.ts +922 -0
- package/connectors/connect-yousign/node_modules/@types/node/domain.d.ts +166 -0
- package/connectors/connect-yousign/node_modules/@types/node/events.d.ts +1047 -0
- package/connectors/connect-yousign/node_modules/@types/node/fs/promises.d.ts +1329 -0
- package/connectors/connect-yousign/node_modules/@types/node/fs.d.ts +4678 -0
- package/connectors/connect-yousign/node_modules/@types/node/globals.d.ts +150 -0
- package/connectors/connect-yousign/node_modules/@types/node/globals.typedarray.d.ts +101 -0
- package/connectors/connect-yousign/node_modules/@types/node/http.d.ts +2188 -0
- package/connectors/connect-yousign/node_modules/@types/node/http2.d.ts +2480 -0
- package/connectors/connect-yousign/node_modules/@types/node/https.d.ts +405 -0
- package/connectors/connect-yousign/node_modules/@types/node/index.d.ts +115 -0
- package/connectors/connect-yousign/node_modules/@types/node/inspector/promises.d.ts +41 -0
- package/connectors/connect-yousign/node_modules/@types/node/inspector.d.ts +269 -0
- package/connectors/connect-yousign/node_modules/@types/node/inspector.generated.d.ts +4401 -0
- package/connectors/connect-yousign/node_modules/@types/node/module.d.ts +757 -0
- package/connectors/connect-yousign/node_modules/@types/node/net.d.ts +933 -0
- package/connectors/connect-yousign/node_modules/@types/node/os.d.ts +507 -0
- package/connectors/connect-yousign/node_modules/@types/node/package.json +155 -0
- package/connectors/connect-yousign/node_modules/@types/node/path/posix.d.ts +8 -0
- package/connectors/connect-yousign/node_modules/@types/node/path/win32.d.ts +8 -0
- package/connectors/connect-yousign/node_modules/@types/node/path.d.ts +187 -0
- package/connectors/connect-yousign/node_modules/@types/node/perf_hooks.d.ts +643 -0
- package/connectors/connect-yousign/node_modules/@types/node/process.d.ts +2175 -0
- package/connectors/connect-yousign/node_modules/@types/node/punycode.d.ts +117 -0
- package/connectors/connect-yousign/node_modules/@types/node/querystring.d.ts +152 -0
- package/connectors/connect-yousign/node_modules/@types/node/quic.d.ts +910 -0
- package/connectors/connect-yousign/node_modules/@types/node/readline/promises.d.ts +161 -0
- package/connectors/connect-yousign/node_modules/@types/node/readline.d.ts +542 -0
- package/connectors/connect-yousign/node_modules/@types/node/repl.d.ts +415 -0
- package/connectors/connect-yousign/node_modules/@types/node/sea.d.ts +162 -0
- package/connectors/connect-yousign/node_modules/@types/node/sqlite.d.ts +1065 -0
- package/connectors/connect-yousign/node_modules/@types/node/stream/consumers.d.ts +38 -0
- package/connectors/connect-yousign/node_modules/@types/node/stream/promises.d.ts +211 -0
- package/connectors/connect-yousign/node_modules/@types/node/stream/web.d.ts +296 -0
- package/connectors/connect-yousign/node_modules/@types/node/stream.d.ts +1770 -0
- package/connectors/connect-yousign/node_modules/@types/node/string_decoder.d.ts +67 -0
- package/connectors/connect-yousign/node_modules/@types/node/test/reporters.d.ts +96 -0
- package/connectors/connect-yousign/node_modules/@types/node/test.d.ts +2275 -0
- package/connectors/connect-yousign/node_modules/@types/node/timers/promises.d.ts +108 -0
- package/connectors/connect-yousign/node_modules/@types/node/timers.d.ts +159 -0
- package/connectors/connect-yousign/node_modules/@types/node/tls.d.ts +1203 -0
- package/connectors/connect-yousign/node_modules/@types/node/trace_events.d.ts +197 -0
- package/connectors/connect-yousign/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +462 -0
- package/connectors/connect-yousign/node_modules/@types/node/ts5.6/compatibility/float16array.d.ts +71 -0
- package/connectors/connect-yousign/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +36 -0
- package/connectors/connect-yousign/node_modules/@types/node/ts5.6/index.d.ts +117 -0
- package/connectors/connect-yousign/node_modules/@types/node/ts5.7/compatibility/float16array.d.ts +72 -0
- package/connectors/connect-yousign/node_modules/@types/node/ts5.7/index.d.ts +117 -0
- package/connectors/connect-yousign/node_modules/@types/node/tty.d.ts +250 -0
- package/connectors/connect-yousign/node_modules/@types/node/url.d.ts +541 -0
- package/connectors/connect-yousign/node_modules/@types/node/util/types.d.ts +558 -0
- package/connectors/connect-yousign/node_modules/@types/node/util.d.ts +1687 -0
- package/connectors/connect-yousign/node_modules/@types/node/v8.d.ts +988 -0
- package/connectors/connect-yousign/node_modules/@types/node/vm.d.ts +1208 -0
- package/connectors/connect-yousign/node_modules/@types/node/wasi.d.ts +202 -0
- package/connectors/connect-yousign/node_modules/@types/node/web-globals/abortcontroller.d.ts +59 -0
- package/connectors/connect-yousign/node_modules/@types/node/web-globals/blob.d.ts +23 -0
- package/connectors/connect-yousign/node_modules/@types/node/web-globals/console.d.ts +9 -0
- package/connectors/connect-yousign/node_modules/@types/node/web-globals/crypto.d.ts +39 -0
- package/connectors/connect-yousign/node_modules/@types/node/web-globals/domexception.d.ts +68 -0
- package/connectors/connect-yousign/node_modules/@types/node/web-globals/encoding.d.ts +11 -0
- package/connectors/connect-yousign/node_modules/@types/node/web-globals/events.d.ts +106 -0
- package/connectors/connect-yousign/node_modules/@types/node/web-globals/fetch.d.ts +69 -0
- package/connectors/connect-yousign/node_modules/@types/node/web-globals/importmeta.d.ts +13 -0
- package/connectors/connect-yousign/node_modules/@types/node/web-globals/messaging.d.ts +23 -0
- package/connectors/connect-yousign/node_modules/@types/node/web-globals/navigator.d.ts +25 -0
- package/connectors/connect-yousign/node_modules/@types/node/web-globals/performance.d.ts +45 -0
- package/connectors/connect-yousign/node_modules/@types/node/web-globals/storage.d.ts +24 -0
- package/connectors/connect-yousign/node_modules/@types/node/web-globals/streams.d.ts +115 -0
- package/connectors/connect-yousign/node_modules/@types/node/web-globals/timers.d.ts +44 -0
- package/connectors/connect-yousign/node_modules/@types/node/web-globals/url.d.ts +24 -0
- package/connectors/connect-yousign/node_modules/@types/node/worker_threads.d.ts +717 -0
- package/connectors/connect-yousign/node_modules/@types/node/zlib.d.ts +682 -0
- package/connectors/connect-yousign/node_modules/bun-types/CLAUDE.md +105 -0
- package/connectors/connect-yousign/node_modules/bun-types/README.md +33 -0
- package/connectors/connect-yousign/node_modules/bun-types/bun.d.ts +8481 -0
- package/connectors/connect-yousign/node_modules/bun-types/bun.ns.d.ts +5 -0
- package/connectors/connect-yousign/node_modules/bun-types/bundle.d.ts +74 -0
- package/connectors/connect-yousign/node_modules/bun-types/deprecated.d.ts +184 -0
- package/connectors/connect-yousign/node_modules/bun-types/devserver.d.ts +187 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/README.md +28 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/bundler/bytecode.mdx +447 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/bundler/css.mdx +1024 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/bundler/esbuild.mdx +304 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/bundler/executables.mdx +1318 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/bundler/fullstack.mdx +1086 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/bundler/hot-reloading.mdx +229 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/bundler/html-static.mdx +498 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/bundler/index.mdx +1840 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/bundler/loaders.mdx +451 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/bundler/macros.mdx +328 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/bundler/minifier.mdx +1286 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/bundler/plugins.mdx +477 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/bundler/standalone-html.mdx +314 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/feedback.mdx +75 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/arraybuffer-to-array.mdx +29 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/arraybuffer-to-blob.mdx +26 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/arraybuffer-to-buffer.mdx +27 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/arraybuffer-to-string.mdx +17 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/arraybuffer-to-typedarray.mdx +41 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/blob-to-arraybuffer.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/blob-to-dataview.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/blob-to-stream.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/blob-to-string.mdx +17 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/blob-to-typedarray.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/buffer-to-arraybuffer.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/buffer-to-blob.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/buffer-to-readablestream.mdx +43 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/buffer-to-string.mdx +27 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/buffer-to-typedarray.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/dataview-to-string.mdx +17 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/typedarray-to-arraybuffer.mdx +27 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/typedarray-to-blob.mdx +18 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/typedarray-to-buffer.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/typedarray-to-dataview.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/typedarray-to-readablestream.mdx +43 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/binary/typedarray-to-string.mdx +18 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/deployment/aws-lambda.mdx +204 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/deployment/digital-ocean.mdx +161 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/deployment/google-cloud-run.mdx +194 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/deployment/railway.mdx +145 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/deployment/render.mdx +82 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/deployment/vercel.mdx +97 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/astro.mdx +82 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/discordjs.mdx +80 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/docker.mdx +151 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/drizzle.mdx +195 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/elysia.mdx +31 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/express.mdx +43 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/gel.mdx +261 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/hono.mdx +47 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/mongoose.mdx +92 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/neon-drizzle.mdx +234 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/neon-serverless-postgres.mdx +60 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/nextjs.mdx +103 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/nuxt.mdx +96 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/pm2.mdx +55 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/prisma-postgres.mdx +169 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/prisma.mdx +164 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/qwik.mdx +114 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/react.mdx +52 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/remix.mdx +97 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/sentry.mdx +54 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/solidstart.mdx +62 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/ssr-react.mdx +49 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/stric.mdx +54 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/sveltekit.mdx +138 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/systemd.mdx +114 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/tanstack-start.mdx +791 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/upstash.mdx +87 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/ecosystem/vite.mdx +77 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/html-rewriter/extract-links.mdx +71 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/html-rewriter/extract-social-meta.mdx +97 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/http/cluster.mdx +69 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/http/fetch-unix.mdx +35 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/http/fetch.mdx +26 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/http/file-uploads.mdx +97 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/http/hot.mdx +28 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/http/proxy.mdx +50 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/http/server.mdx +48 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/http/simple.mdx +20 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/http/stream-file.mdx +50 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/http/stream-iterator.mdx +49 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/http/stream-node-streams-in-bun.mdx +22 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/http/tls.mdx +32 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/index.mdx +10 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/add-dev.mdx +28 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/add-git.mdx +40 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/add-optional.mdx +27 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/add-peer.mdx +45 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/add-tarball.mdx +35 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/add.mdx +44 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/azure-artifacts.mdx +76 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/cicd.mdx +43 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/custom-registry.mdx +32 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/from-npm-install-to-bun-install.mdx +230 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/git-diff-bun-lockfile.mdx +48 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/jfrog-artifactory.mdx +28 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/npm-alias.mdx +25 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/registry-scope.mdx +40 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/trusted.mdx +52 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/workspaces.mdx +70 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/install/yarnlock.mdx +51 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/process/argv.mdx +66 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/process/ctrl-c.mdx +18 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/process/ipc.mdx +69 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/process/nanoseconds.mdx +15 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/process/os-signals.mdx +31 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/process/spawn-stderr.mdx +34 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/process/spawn-stdout.mdx +28 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/process/spawn.mdx +43 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/process/stdin.mdx +62 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/read-file/arraybuffer.mdx +30 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/read-file/buffer.mdx +21 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/read-file/exists.mdx +18 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/read-file/json.mdx +19 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/read-file/mime.mdx +22 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/read-file/stream.mdx +28 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/read-file/string.mdx +24 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/read-file/uint8array.mdx +23 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/read-file/watch.mdx +66 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/build-time-constants.mdx +295 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/cicd.mdx +45 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/codesign-macos-executable.mdx +61 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/define-constant.mdx +149 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/delete-directory.mdx +39 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/delete-file.mdx +21 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/heap-snapshot.mdx +28 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/import-html.mdx +15 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/import-json.mdx +46 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/import-json5.mdx +74 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/import-toml.mdx +32 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/import-yaml.mdx +104 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/read-env.mdx +37 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/set-env.mdx +51 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/shell.mdx +42 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/timezone.mdx +38 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/tsconfig-paths.mdx +31 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/typescript.mdx +51 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/vscode-debugger.mdx +47 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/runtime/web-debugger.mdx +103 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/streams/node-readable-to-arraybuffer.mdx +13 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/streams/node-readable-to-blob.mdx +13 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/streams/node-readable-to-json.mdx +14 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/streams/node-readable-to-string.mdx +14 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/streams/node-readable-to-uint8array.mdx +13 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/streams/to-array.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/streams/to-arraybuffer.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/streams/to-blob.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/streams/to-buffer.mdx +17 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/streams/to-json.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/streams/to-string.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/streams/to-typedarray.mdx +24 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/bail.mdx +24 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/concurrent-test-glob.mdx +146 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/coverage-threshold.mdx +67 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/coverage.mdx +49 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/happy-dom.mdx +73 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/migrate-from-jest.mdx +125 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/mock-clock.mdx +50 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/mock-functions.mdx +70 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/rerun-each.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/run-tests.mdx +116 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/skip-tests.mdx +43 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/snapshot.mdx +102 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/spy-on.mdx +49 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/svelte-test.mdx +113 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/testing-library.mdx +93 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/timeout.mdx +17 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/todo-tests.mdx +74 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/update-snapshots.mdx +49 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/test/watch-mode.mdx +24 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/base64.mdx +17 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/deep-equals.mdx +41 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/deflate.mdx +20 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/detect-bun.mdx +28 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/entrypoint.mdx +19 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/escape-html.mdx +24 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/file-url-to-path.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/gzip.mdx +20 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/hash-a-password.mdx +56 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/import-meta-dir.mdx +15 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/import-meta-file.mdx +15 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/import-meta-path.mdx +15 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/javascript-uuid.mdx +25 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/main.mdx +43 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/path-to-file-url.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/sleep.mdx +24 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/upgrade.mdx +93 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/version.mdx +23 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/util/which-path-to-executable-bin.mdx +17 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/websocket/compression.mdx +33 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/websocket/context.mdx +79 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/websocket/pubsub.mdx +43 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/websocket/simple.mdx +38 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/write-file/append.mdx +54 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/write-file/basic.mdx +46 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/write-file/blob.mdx +30 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/write-file/cat.mdx +19 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/write-file/file-cp.mdx +18 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/write-file/filesink.mdx +54 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/write-file/response.mdx +19 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/write-file/stdout.mdx +23 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/write-file/stream.mdx +19 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/guides/write-file/unlink.mdx +18 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/index.mdx +133 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/installation.mdx +372 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/bunx.mdx +91 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/catalogs.mdx +292 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/cli/add.mdx +179 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/cli/audit.mdx +60 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/cli/info.mdx +70 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/cli/install.mdx +591 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/cli/link.mdx +61 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/cli/outdated.mdx +197 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/cli/patch.mdx +69 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/cli/pm.mdx +323 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/cli/publish.mdx +131 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/cli/remove.mdx +16 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/cli/update.mdx +140 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/cli/why.mdx +84 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/filter.mdx +127 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/global-cache.mdx +72 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/isolated-installs.mdx +220 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/lifecycle.mdx +64 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/lockfile.mdx +64 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/npmrc.mdx +245 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/overrides.mdx +83 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/scopes-registries.mdx +35 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/security-scanner-api.mdx +95 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/pm/workspaces.mdx +115 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/project/benchmarking.mdx +296 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/project/bindgen.mdx +223 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/project/building-windows.mdx +143 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/project/contributing.mdx +366 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/project/feedback.mdx +20 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/project/license.mdx +78 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/project/roadmap.mdx +8 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/quickstart.mdx +251 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/archive.mdx +452 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/auto-install.mdx +97 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/binary-data.mdx +846 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/bun-apis.mdx +59 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/bunfig.mdx +754 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/c-compiler.mdx +204 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/child-process.mdx +659 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/color.mdx +267 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/console.mdx +67 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/cookies.mdx +454 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/debugger.mdx +335 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/environment-variables.mdx +231 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/ffi.mdx +567 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/file-io.mdx +306 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/file-system-router.mdx +118 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/file-types.mdx +482 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/glob.mdx +181 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/globals.mdx +72 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/hashing.mdx +315 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/html-rewriter.mdx +333 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/http/cookies.mdx +79 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/http/error-handling.mdx +40 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/http/metrics.mdx +36 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/http/routing.mdx +289 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/http/server.mdx +645 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/http/tls.mdx +101 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/http/websockets.mdx +414 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/index.mdx +223 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/json5.mdx +271 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/jsonl.mdx +188 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/jsx.mdx +115 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/markdown.mdx +344 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/module-resolution.mdx +374 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/networking/dns.mdx +111 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/networking/fetch.mdx +484 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/networking/tcp.mdx +239 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/networking/udp.mdx +180 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/node-api.mdx +19 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/nodejs-compat.mdx +468 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/plugins.mdx +419 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/redis.mdx +583 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/repl.mdx +176 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/s3.mdx +881 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/secrets.mdx +340 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/semver.mdx +57 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/shell.mdx +637 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/sql.mdx +1404 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/sqlite.mdx +721 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/streams.mdx +232 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/templating/create.mdx +269 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/templating/init.mdx +58 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/transpiler.mdx +288 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/typescript.mdx +58 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/utils.mdx +1010 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/watch-mode.mdx +161 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/web-apis.mdx +29 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/workers.mdx +314 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/runtime/yaml.mdx +469 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/snippets/cli/add.mdx +166 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/snippets/cli/build.mdx +197 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/snippets/cli/bunx.mdx +49 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/snippets/cli/feedback.mdx +17 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/snippets/cli/init.mdx +84 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/snippets/cli/install.mdx +173 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/snippets/cli/link.mdx +163 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/snippets/cli/outdated.mdx +140 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/snippets/cli/patch.mdx +171 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/snippets/cli/publish.mdx +198 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/snippets/cli/remove.mdx +146 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/snippets/cli/run.mdx +305 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/snippets/cli/test.mdx +105 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/snippets/cli/update.mdx +144 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/test/code-coverage.mdx +409 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/test/configuration.mdx +520 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/test/dates-times.mdx +129 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/test/discovery.mdx +90 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/test/dom.mdx +226 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/test/index.mdx +409 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/test/lifecycle.mdx +366 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/test/mocks.mdx +637 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/test/reporters.mdx +126 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/test/runtime-behavior.mdx +342 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/test/snapshots.mdx +434 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/test/writing-tests.mdx +672 -0
- package/connectors/connect-yousign/node_modules/bun-types/docs/typescript.mdx +54 -0
- package/connectors/connect-yousign/node_modules/bun-types/extensions.d.ts +40 -0
- package/connectors/connect-yousign/node_modules/bun-types/fetch.d.ts +79 -0
- package/connectors/connect-yousign/node_modules/bun-types/ffi.d.ts +1154 -0
- package/connectors/connect-yousign/node_modules/bun-types/globals.d.ts +2067 -0
- package/connectors/connect-yousign/node_modules/bun-types/html-rewriter.d.ts +186 -0
- package/connectors/connect-yousign/node_modules/bun-types/index.d.ts +32 -0
- package/connectors/connect-yousign/node_modules/bun-types/jsc.d.ts +233 -0
- package/connectors/connect-yousign/node_modules/bun-types/jsx.d.ts +11 -0
- package/connectors/connect-yousign/node_modules/bun-types/overrides.d.ts +376 -0
- package/connectors/connect-yousign/node_modules/bun-types/package.json +37 -0
- package/connectors/connect-yousign/node_modules/bun-types/redis.d.ts +3352 -0
- package/connectors/connect-yousign/node_modules/bun-types/s3.d.ts +1335 -0
- package/connectors/connect-yousign/node_modules/bun-types/security.d.ts +101 -0
- package/connectors/connect-yousign/node_modules/bun-types/serve.d.ts +1296 -0
- package/connectors/connect-yousign/node_modules/bun-types/shell.d.ts +380 -0
- package/connectors/connect-yousign/node_modules/bun-types/sql.d.ts +887 -0
- package/connectors/connect-yousign/node_modules/bun-types/sqlite.d.ts +1322 -0
- package/connectors/connect-yousign/node_modules/bun-types/test-globals.d.ts +22 -0
- package/connectors/connect-yousign/node_modules/bun-types/test.d.ts +2392 -0
- package/connectors/connect-yousign/node_modules/bun-types/vendor/expect-type/branding.d.ts +283 -0
- package/connectors/connect-yousign/node_modules/bun-types/vendor/expect-type/index.d.ts +1207 -0
- package/connectors/connect-yousign/node_modules/bun-types/vendor/expect-type/messages.d.ts +395 -0
- package/connectors/connect-yousign/node_modules/bun-types/vendor/expect-type/overloads.d.ts +669 -0
- package/connectors/connect-yousign/node_modules/bun-types/vendor/expect-type/utils.d.ts +431 -0
- package/connectors/connect-yousign/node_modules/bun-types/wasm.d.ts +193 -0
- package/connectors/connect-yousign/node_modules/chalk/license +9 -0
- package/connectors/connect-yousign/node_modules/chalk/package.json +83 -0
- package/connectors/connect-yousign/node_modules/chalk/readme.md +297 -0
- package/connectors/connect-yousign/node_modules/chalk/source/index.d.ts +325 -0
- package/connectors/connect-yousign/node_modules/chalk/source/index.js +225 -0
- package/connectors/connect-yousign/node_modules/chalk/source/utilities.js +33 -0
- package/connectors/connect-yousign/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
- package/connectors/connect-yousign/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
- package/connectors/connect-yousign/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
- package/connectors/connect-yousign/node_modules/chalk/source/vendor/supports-color/browser.js +34 -0
- package/connectors/connect-yousign/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
- package/connectors/connect-yousign/node_modules/chalk/source/vendor/supports-color/index.js +190 -0
- package/connectors/connect-yousign/node_modules/commander/LICENSE +22 -0
- package/connectors/connect-yousign/node_modules/commander/Readme.md +1157 -0
- package/connectors/connect-yousign/node_modules/commander/esm.mjs +16 -0
- package/connectors/connect-yousign/node_modules/commander/index.js +24 -0
- package/connectors/connect-yousign/node_modules/commander/lib/argument.js +149 -0
- package/connectors/connect-yousign/node_modules/commander/lib/command.js +2509 -0
- package/connectors/connect-yousign/node_modules/commander/lib/error.js +39 -0
- package/connectors/connect-yousign/node_modules/commander/lib/help.js +520 -0
- package/connectors/connect-yousign/node_modules/commander/lib/option.js +330 -0
- package/connectors/connect-yousign/node_modules/commander/lib/suggestSimilar.js +101 -0
- package/connectors/connect-yousign/node_modules/commander/package-support.json +16 -0
- package/connectors/connect-yousign/node_modules/commander/package.json +84 -0
- package/connectors/connect-yousign/node_modules/commander/typings/esm.d.mts +3 -0
- package/connectors/connect-yousign/node_modules/commander/typings/index.d.ts +969 -0
- package/connectors/connect-yousign/node_modules/typescript/LICENSE.txt +55 -0
- package/connectors/connect-yousign/node_modules/typescript/README.md +50 -0
- package/connectors/connect-yousign/node_modules/typescript/SECURITY.md +41 -0
- package/connectors/connect-yousign/node_modules/typescript/ThirdPartyNoticeText.txt +193 -0
- package/connectors/connect-yousign/node_modules/typescript/bin/tsc +2 -0
- package/connectors/connect-yousign/node_modules/typescript/bin/tsserver +2 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/_tsc.js +133818 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/_tsserver.js +659 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/_typingsInstaller.js +222 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/cs/diagnosticMessages.generated.json +2122 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/de/diagnosticMessages.generated.json +2122 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/es/diagnosticMessages.generated.json +2122 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/fr/diagnosticMessages.generated.json +2122 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/it/diagnosticMessages.generated.json +2122 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/ja/diagnosticMessages.generated.json +2122 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/ko/diagnosticMessages.generated.json +2122 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.d.ts +22 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.decorators.d.ts +384 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.decorators.legacy.d.ts +22 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.dom.asynciterable.d.ts +41 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.dom.d.ts +39429 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.dom.iterable.d.ts +571 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2015.collection.d.ts +147 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2015.core.d.ts +597 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2015.d.ts +28 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2015.generator.d.ts +77 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2015.iterable.d.ts +605 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2015.promise.d.ts +81 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2015.proxy.d.ts +128 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2015.reflect.d.ts +144 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2015.symbol.d.ts +46 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts +326 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2016.array.include.d.ts +116 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2016.d.ts +21 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2016.full.d.ts +23 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2016.intl.d.ts +31 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts +21 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2017.d.ts +26 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2017.date.d.ts +31 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2017.full.d.ts +23 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2017.intl.d.ts +44 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2017.object.d.ts +49 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts +135 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2017.string.d.ts +45 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts +53 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts +77 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts +53 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2018.d.ts +24 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2018.full.d.ts +24 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2018.intl.d.ts +83 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2018.promise.d.ts +30 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2018.regexp.d.ts +37 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2019.array.d.ts +79 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2019.d.ts +24 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2019.full.d.ts +24 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2019.intl.d.ts +23 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2019.object.d.ts +33 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2019.string.d.ts +37 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2019.symbol.d.ts +24 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2020.bigint.d.ts +765 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2020.d.ts +27 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2020.date.d.ts +42 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2020.full.d.ts +24 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2020.intl.d.ts +474 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2020.number.d.ts +28 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2020.promise.d.ts +47 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts +99 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2020.string.d.ts +44 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts +41 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2021.d.ts +23 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2021.full.d.ts +24 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2021.intl.d.ts +166 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2021.promise.d.ts +48 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2021.string.d.ts +33 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2021.weakref.d.ts +78 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2022.array.d.ts +121 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2022.d.ts +25 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2022.error.d.ts +75 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2022.full.d.ts +24 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2022.intl.d.ts +145 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2022.object.d.ts +26 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2022.regexp.d.ts +39 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2022.string.d.ts +25 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2023.array.d.ts +924 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2023.collection.d.ts +21 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2023.d.ts +22 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2023.full.d.ts +24 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2023.intl.d.ts +56 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts +65 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2024.collection.d.ts +29 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2024.d.ts +26 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2024.full.d.ts +24 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2024.object.d.ts +29 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2024.promise.d.ts +35 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2024.regexp.d.ts +25 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts +68 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es2024.string.d.ts +29 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es5.d.ts +4601 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.es6.d.ts +23 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.esnext.array.d.ts +35 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.esnext.collection.d.ts +96 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.esnext.d.ts +29 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.esnext.decorators.d.ts +28 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.esnext.disposable.d.ts +193 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.esnext.error.d.ts +24 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.esnext.float16.d.ts +445 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.esnext.full.d.ts +24 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.esnext.intl.d.ts +21 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.esnext.iterator.d.ts +148 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.esnext.promise.d.ts +34 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts +25 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.scripthost.d.ts +322 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.webworker.asynciterable.d.ts +41 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.webworker.d.ts +13150 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.webworker.importscripts.d.ts +23 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/lib.webworker.iterable.d.ts +340 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/pl/diagnosticMessages.generated.json +2122 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/pt-br/diagnosticMessages.generated.json +2122 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/ru/diagnosticMessages.generated.json +2122 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/tr/diagnosticMessages.generated.json +2122 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/tsc.js +8 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/tsserver.js +8 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/tsserverlibrary.d.ts +17 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/tsserverlibrary.js +21 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/typesMap.json +497 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/typescript.d.ts +11437 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/typescript.js +200276 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/typingsInstaller.js +8 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/watchGuard.js +53 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/zh-cn/diagnosticMessages.generated.json +2122 -0
- package/connectors/connect-yousign/node_modules/typescript/lib/zh-tw/diagnosticMessages.generated.json +2122 -0
- package/connectors/connect-yousign/node_modules/typescript/package.json +120 -0
- package/connectors/connect-yousign/node_modules/undici-types/LICENSE +21 -0
- package/connectors/connect-yousign/node_modules/undici-types/README.md +6 -0
- package/connectors/connect-yousign/node_modules/undici-types/agent.d.ts +32 -0
- package/connectors/connect-yousign/node_modules/undici-types/api.d.ts +43 -0
- package/connectors/connect-yousign/node_modules/undici-types/balanced-pool.d.ts +30 -0
- package/connectors/connect-yousign/node_modules/undici-types/cache-interceptor.d.ts +173 -0
- package/connectors/connect-yousign/node_modules/undici-types/cache.d.ts +36 -0
- package/connectors/connect-yousign/node_modules/undici-types/client-stats.d.ts +15 -0
- package/connectors/connect-yousign/node_modules/undici-types/client.d.ts +108 -0
- package/connectors/connect-yousign/node_modules/undici-types/connector.d.ts +34 -0
- package/connectors/connect-yousign/node_modules/undici-types/content-type.d.ts +21 -0
- package/connectors/connect-yousign/node_modules/undici-types/cookies.d.ts +30 -0
- package/connectors/connect-yousign/node_modules/undici-types/diagnostics-channel.d.ts +74 -0
- package/connectors/connect-yousign/node_modules/undici-types/dispatcher.d.ts +276 -0
- package/connectors/connect-yousign/node_modules/undici-types/env-http-proxy-agent.d.ts +22 -0
- package/connectors/connect-yousign/node_modules/undici-types/errors.d.ts +161 -0
- package/connectors/connect-yousign/node_modules/undici-types/eventsource.d.ts +66 -0
- package/connectors/connect-yousign/node_modules/undici-types/fetch.d.ts +211 -0
- package/connectors/connect-yousign/node_modules/undici-types/formdata.d.ts +108 -0
- package/connectors/connect-yousign/node_modules/undici-types/global-dispatcher.d.ts +9 -0
- package/connectors/connect-yousign/node_modules/undici-types/global-origin.d.ts +7 -0
- package/connectors/connect-yousign/node_modules/undici-types/h2c-client.d.ts +73 -0
- package/connectors/connect-yousign/node_modules/undici-types/handlers.d.ts +15 -0
- package/connectors/connect-yousign/node_modules/undici-types/header.d.ts +160 -0
- package/connectors/connect-yousign/node_modules/undici-types/index.d.ts +88 -0
- package/connectors/connect-yousign/node_modules/undici-types/interceptors.d.ts +73 -0
- package/connectors/connect-yousign/node_modules/undici-types/mock-agent.d.ts +68 -0
- package/connectors/connect-yousign/node_modules/undici-types/mock-call-history.d.ts +111 -0
- package/connectors/connect-yousign/node_modules/undici-types/mock-client.d.ts +27 -0
- package/connectors/connect-yousign/node_modules/undici-types/mock-errors.d.ts +12 -0
- package/connectors/connect-yousign/node_modules/undici-types/mock-interceptor.d.ts +94 -0
- package/connectors/connect-yousign/node_modules/undici-types/mock-pool.d.ts +27 -0
- package/connectors/connect-yousign/node_modules/undici-types/package.json +55 -0
- package/connectors/connect-yousign/node_modules/undici-types/patch.d.ts +29 -0
- package/connectors/connect-yousign/node_modules/undici-types/pool-stats.d.ts +19 -0
- package/connectors/connect-yousign/node_modules/undici-types/pool.d.ts +41 -0
- package/connectors/connect-yousign/node_modules/undici-types/proxy-agent.d.ts +29 -0
- package/connectors/connect-yousign/node_modules/undici-types/readable.d.ts +68 -0
- package/connectors/connect-yousign/node_modules/undici-types/retry-agent.d.ts +8 -0
- package/connectors/connect-yousign/node_modules/undici-types/retry-handler.d.ts +125 -0
- package/connectors/connect-yousign/node_modules/undici-types/round-robin-pool.d.ts +41 -0
- package/connectors/connect-yousign/node_modules/undici-types/snapshot-agent.d.ts +109 -0
- package/connectors/connect-yousign/node_modules/undici-types/util.d.ts +18 -0
- package/connectors/connect-yousign/node_modules/undici-types/utility.d.ts +7 -0
- package/connectors/connect-yousign/node_modules/undici-types/webidl.d.ts +341 -0
- package/connectors/connect-yousign/node_modules/undici-types/websocket.d.ts +186 -0
- package/connectors/connect-yousign/package.json +52 -0
- package/connectors/connect-yousign/src/api/client.ts +119 -0
- package/connectors/connect-yousign/src/api/index.ts +221 -0
- package/connectors/connect-yousign/src/cli/index.ts +555 -0
- package/connectors/connect-yousign/src/index.ts +21 -0
- package/connectors/connect-yousign/src/types/index.ts +275 -0
- package/connectors/connect-yousign/src/utils/config.ts +121 -0
- package/connectors/connect-yousign/tsconfig.json +16 -0
- package/dist/index.js +7 -0
- package/package.json +1 -1
|
@@ -0,0 +1,2447 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import open from 'open';
|
|
5
|
+
import { Gmail } from '../api';
|
|
6
|
+
import {
|
|
7
|
+
getClientId,
|
|
8
|
+
getClientSecret,
|
|
9
|
+
setCredentials,
|
|
10
|
+
clearConfig,
|
|
11
|
+
isAuthenticated,
|
|
12
|
+
loadTokens,
|
|
13
|
+
saveTokens,
|
|
14
|
+
getUserEmail,
|
|
15
|
+
setUserEmail,
|
|
16
|
+
getUserName,
|
|
17
|
+
setUserName,
|
|
18
|
+
getConfigDir,
|
|
19
|
+
getBaseConfigDir,
|
|
20
|
+
setProfileOverride,
|
|
21
|
+
getCurrentProfile,
|
|
22
|
+
setCurrentProfile,
|
|
23
|
+
listProfiles,
|
|
24
|
+
createProfile,
|
|
25
|
+
deleteProfile,
|
|
26
|
+
profileExists,
|
|
27
|
+
} from '../utils/config';
|
|
28
|
+
import {
|
|
29
|
+
getAuthUrl,
|
|
30
|
+
startCallbackServer,
|
|
31
|
+
} from '../utils/auth';
|
|
32
|
+
import {
|
|
33
|
+
saveContact,
|
|
34
|
+
getContact,
|
|
35
|
+
getAllContacts,
|
|
36
|
+
deleteContact,
|
|
37
|
+
searchContacts,
|
|
38
|
+
type Contact,
|
|
39
|
+
} from '../utils/contacts';
|
|
40
|
+
import {
|
|
41
|
+
loadSettings,
|
|
42
|
+
saveSettings,
|
|
43
|
+
setSetting,
|
|
44
|
+
setSignature,
|
|
45
|
+
type Settings,
|
|
46
|
+
} from '../utils/settings';
|
|
47
|
+
import type { OutputFormat } from '../utils/output';
|
|
48
|
+
import { success, error, info, print, warn } from '../utils/output';
|
|
49
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
50
|
+
import { join, resolve, extname, basename } from 'path';
|
|
51
|
+
|
|
52
|
+
const program = new Command();
|
|
53
|
+
|
|
54
|
+
program
|
|
55
|
+
.name('connect-gmail')
|
|
56
|
+
.description('Gmail API connector CLI - Send, read, and manage Gmail with ease')
|
|
57
|
+
.version('0.1.0')
|
|
58
|
+
.option('-f, --format <format>', 'Output format (json, table, pretty)', 'pretty')
|
|
59
|
+
.option('-p, --profile <profile>', 'Use a specific profile')
|
|
60
|
+
.hook('preAction', (thisCommand) => {
|
|
61
|
+
// Set profile override before any command runs
|
|
62
|
+
const opts = thisCommand.opts();
|
|
63
|
+
if (opts.profile) {
|
|
64
|
+
if (!profileExists(opts.profile)) {
|
|
65
|
+
error(`Profile "${opts.profile}" does not exist. Create it with "connect-gmail profiles create ${opts.profile}"`);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
setProfileOverride(opts.profile);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Helper to get output format
|
|
73
|
+
function getFormat(cmd: Command): OutputFormat {
|
|
74
|
+
const parent = cmd.parent;
|
|
75
|
+
return (parent?.opts().format || 'pretty') as OutputFormat;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Helper to check authentication
|
|
79
|
+
function requireAuth(): Gmail {
|
|
80
|
+
// isAuthenticated() checks for both accessToken and refreshToken.
|
|
81
|
+
// If accessToken is missing/expired but refreshToken exists, the client's
|
|
82
|
+
// getValidAccessToken() will handle the refresh automatically.
|
|
83
|
+
const tokens = loadTokens();
|
|
84
|
+
if (!tokens || (!tokens.accessToken && !tokens.refreshToken)) {
|
|
85
|
+
error('Not authenticated. Run "connect-gmail auth login" first.');
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
return Gmail.create();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ============================================
|
|
92
|
+
// Auth Commands
|
|
93
|
+
// ============================================
|
|
94
|
+
const authCmd = program
|
|
95
|
+
.command('auth')
|
|
96
|
+
.description('Authentication commands');
|
|
97
|
+
|
|
98
|
+
authCmd
|
|
99
|
+
.command('login')
|
|
100
|
+
.description('Login to Gmail via OAuth2 (opens browser) - auto-creates profile from email')
|
|
101
|
+
.action(async () => {
|
|
102
|
+
const clientId = getClientId();
|
|
103
|
+
const clientSecret = getClientSecret();
|
|
104
|
+
|
|
105
|
+
if (!clientId || !clientSecret) {
|
|
106
|
+
error('OAuth credentials not configured.');
|
|
107
|
+
info('Run "connect-gmail config set-credentials <client-id> <client-secret>" first.');
|
|
108
|
+
info('Or set GMAIL_CLIENT_ID and GMAIL_CLIENT_SECRET environment variables.');
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
info('Starting OAuth2 authentication flow...');
|
|
113
|
+
info('A browser window will open for you to authorize the application.');
|
|
114
|
+
|
|
115
|
+
// Start callback server first
|
|
116
|
+
const serverPromise = startCallbackServer();
|
|
117
|
+
|
|
118
|
+
// Open browser to auth URL
|
|
119
|
+
const authUrl = getAuthUrl();
|
|
120
|
+
await open(authUrl);
|
|
121
|
+
|
|
122
|
+
info('Waiting for authentication...');
|
|
123
|
+
|
|
124
|
+
const result = await serverPromise;
|
|
125
|
+
|
|
126
|
+
if (result.success) {
|
|
127
|
+
success('Successfully authenticated!');
|
|
128
|
+
|
|
129
|
+
// Save tokens to the currently active profile
|
|
130
|
+
if (result.tokens) {
|
|
131
|
+
saveTokens(result.tokens);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Fetch user email and display name, save to the active profile
|
|
135
|
+
try {
|
|
136
|
+
const gmail = Gmail.create();
|
|
137
|
+
const profile = await gmail.profile.get();
|
|
138
|
+
const email = profile.emailAddress;
|
|
139
|
+
setUserEmail(email);
|
|
140
|
+
info(`Email: ${email}`);
|
|
141
|
+
|
|
142
|
+
// Try to get display name from Gmail send-as settings
|
|
143
|
+
try {
|
|
144
|
+
const displayName = await gmail.profile.getDisplayName();
|
|
145
|
+
if (displayName) {
|
|
146
|
+
setUserName(displayName);
|
|
147
|
+
info(`Name: ${displayName}`);
|
|
148
|
+
}
|
|
149
|
+
} catch {
|
|
150
|
+
// Display name fetch failed — not critical
|
|
151
|
+
}
|
|
152
|
+
} catch (err) {
|
|
153
|
+
// Email fetch failed but auth succeeded — tokens are saved
|
|
154
|
+
warn(`Could not fetch email address: ${err}`);
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
error(`Authentication failed: ${result.error}`);
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
authCmd
|
|
163
|
+
.command('status')
|
|
164
|
+
.description('Check authentication status')
|
|
165
|
+
.action(async () => {
|
|
166
|
+
if (isAuthenticated()) {
|
|
167
|
+
const tokens = loadTokens();
|
|
168
|
+
const email = getUserEmail();
|
|
169
|
+
success('Authenticated');
|
|
170
|
+
if (email) {
|
|
171
|
+
info(`Email: ${email}`);
|
|
172
|
+
}
|
|
173
|
+
if (tokens) {
|
|
174
|
+
const expiresIn = Math.max(0, Math.floor((tokens.expiresAt - Date.now()) / 1000 / 60));
|
|
175
|
+
info(`Access token expires in: ${expiresIn} minutes`);
|
|
176
|
+
info(`Has refresh token: ${tokens.refreshToken ? 'Yes' : 'No'}`);
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
warn('Not authenticated');
|
|
180
|
+
info('Run "connect-gmail auth login" to authenticate.');
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
authCmd
|
|
185
|
+
.command('logout')
|
|
186
|
+
.description('Clear stored authentication tokens')
|
|
187
|
+
.action(() => {
|
|
188
|
+
clearConfig();
|
|
189
|
+
success('Logged out successfully');
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// ============================================
|
|
193
|
+
// Config Commands
|
|
194
|
+
// ============================================
|
|
195
|
+
const configCmd = program
|
|
196
|
+
.command('config')
|
|
197
|
+
.description('Manage CLI configuration');
|
|
198
|
+
|
|
199
|
+
configCmd
|
|
200
|
+
.command('set-credentials <clientId> <clientSecret>')
|
|
201
|
+
.description('Set OAuth2 client credentials')
|
|
202
|
+
.action((clientId: string, clientSecret: string) => {
|
|
203
|
+
setCredentials(clientId, clientSecret);
|
|
204
|
+
success('OAuth credentials saved successfully');
|
|
205
|
+
info(`Config stored in: ${getConfigDir()}`);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
configCmd
|
|
209
|
+
.command('set-name <name>')
|
|
210
|
+
.description('Set your display name for sending emails (e.g., "John Doe")')
|
|
211
|
+
.action((name: string) => {
|
|
212
|
+
setUserName(name);
|
|
213
|
+
success(`Display name set to: ${name}`);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
configCmd
|
|
217
|
+
.command('show')
|
|
218
|
+
.description('Show current configuration')
|
|
219
|
+
.action(() => {
|
|
220
|
+
const clientId = getClientId();
|
|
221
|
+
const clientSecret = getClientSecret();
|
|
222
|
+
const email = getUserEmail();
|
|
223
|
+
const name = getUserName();
|
|
224
|
+
const tokens = loadTokens();
|
|
225
|
+
const settings = loadSettings();
|
|
226
|
+
|
|
227
|
+
info(`Config directory: ${getConfigDir()}`);
|
|
228
|
+
info(`Client ID: ${clientId ? `${clientId.substring(0, 20)}...` : chalk.gray('not set')}`);
|
|
229
|
+
info(`Client Secret: ${clientSecret ? '********' : chalk.gray('not set')}`);
|
|
230
|
+
info(`Authenticated: ${isAuthenticated() ? chalk.green('Yes') : chalk.red('No')}`);
|
|
231
|
+
if (email) {
|
|
232
|
+
info(`Email: ${email}`);
|
|
233
|
+
}
|
|
234
|
+
if (name) {
|
|
235
|
+
info(`Display Name: ${name}`);
|
|
236
|
+
}
|
|
237
|
+
if (tokens) {
|
|
238
|
+
info(`Token expires: ${new Date(tokens.expiresAt).toLocaleString()}`);
|
|
239
|
+
}
|
|
240
|
+
info(`Markdown enabled: ${settings.markdownEnabled ? 'Yes' : 'No'}`);
|
|
241
|
+
info(`Append signature: ${settings.appendSignature ? 'Yes' : 'No'}`);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
configCmd
|
|
245
|
+
.command('clear')
|
|
246
|
+
.description('Clear all configuration and tokens')
|
|
247
|
+
.action(() => {
|
|
248
|
+
clearConfig();
|
|
249
|
+
success('Configuration cleared');
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// ============================================
|
|
253
|
+
// Me Command (Gmail profile info)
|
|
254
|
+
// ============================================
|
|
255
|
+
program
|
|
256
|
+
.command('me')
|
|
257
|
+
.description('Get your Gmail profile information')
|
|
258
|
+
.action(async () => {
|
|
259
|
+
try {
|
|
260
|
+
const gmail = requireAuth();
|
|
261
|
+
const profile = await gmail.profile.get();
|
|
262
|
+
print(profile, getFormat(program));
|
|
263
|
+
} catch (err) {
|
|
264
|
+
error(String(err));
|
|
265
|
+
process.exit(1);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// ============================================
|
|
270
|
+
// Profiles Management Commands
|
|
271
|
+
// ============================================
|
|
272
|
+
const profilesCmd = program
|
|
273
|
+
.command('profiles')
|
|
274
|
+
.description('Manage multiple Gmail profiles');
|
|
275
|
+
|
|
276
|
+
profilesCmd
|
|
277
|
+
.command('list')
|
|
278
|
+
.description('List all profiles')
|
|
279
|
+
.action(() => {
|
|
280
|
+
try {
|
|
281
|
+
const profiles = listProfiles();
|
|
282
|
+
const current = getCurrentProfile();
|
|
283
|
+
|
|
284
|
+
if (profiles.length === 0) {
|
|
285
|
+
info('No profiles found');
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
success(`${profiles.length} profile(s):`);
|
|
290
|
+
for (const p of profiles) {
|
|
291
|
+
if (p === current) {
|
|
292
|
+
info(` ${chalk.green('→')} ${p} ${chalk.gray('(current)')}`);
|
|
293
|
+
} else {
|
|
294
|
+
info(` ${p}`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
} catch (err) {
|
|
298
|
+
error(String(err));
|
|
299
|
+
process.exit(1);
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
profilesCmd
|
|
304
|
+
.command('current')
|
|
305
|
+
.description('Show current profile')
|
|
306
|
+
.action(() => {
|
|
307
|
+
const current = getCurrentProfile();
|
|
308
|
+
info(`Current profile: ${chalk.green(current)}`);
|
|
309
|
+
info(`Config directory: ${getConfigDir()}`);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
profilesCmd
|
|
313
|
+
.command('create <name>')
|
|
314
|
+
.description('Create a new profile')
|
|
315
|
+
.action((name: string) => {
|
|
316
|
+
try {
|
|
317
|
+
createProfile(name);
|
|
318
|
+
success(`Profile "${name}" created`);
|
|
319
|
+
info(`Switch to it with: connect-gmail profiles switch ${name}`);
|
|
320
|
+
} catch (err) {
|
|
321
|
+
error(String(err));
|
|
322
|
+
process.exit(1);
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
profilesCmd
|
|
327
|
+
.command('switch <name>')
|
|
328
|
+
.alias('use')
|
|
329
|
+
.description('Switch to a different profile')
|
|
330
|
+
.action((name: string) => {
|
|
331
|
+
try {
|
|
332
|
+
setCurrentProfile(name);
|
|
333
|
+
success(`Switched to profile "${name}"`);
|
|
334
|
+
info(`Config directory: ${getConfigDir()}`);
|
|
335
|
+
|
|
336
|
+
// Show auth status for the new profile
|
|
337
|
+
if (isAuthenticated()) {
|
|
338
|
+
const email = getUserEmail();
|
|
339
|
+
if (email) {
|
|
340
|
+
info(`Logged in as: ${email}`);
|
|
341
|
+
}
|
|
342
|
+
} else {
|
|
343
|
+
warn('Profile not authenticated. Run "connect-gmail auth login"');
|
|
344
|
+
}
|
|
345
|
+
} catch (err) {
|
|
346
|
+
error(String(err));
|
|
347
|
+
process.exit(1);
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
profilesCmd
|
|
352
|
+
.command('delete <name>')
|
|
353
|
+
.description('Delete a profile')
|
|
354
|
+
.action((name: string) => {
|
|
355
|
+
try {
|
|
356
|
+
deleteProfile(name);
|
|
357
|
+
success(`Profile "${name}" deleted`);
|
|
358
|
+
} catch (err) {
|
|
359
|
+
error(String(err));
|
|
360
|
+
process.exit(1);
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
profilesCmd
|
|
365
|
+
.command('show')
|
|
366
|
+
.description('Show all profiles with their status')
|
|
367
|
+
.action(async () => {
|
|
368
|
+
try {
|
|
369
|
+
const profiles = listProfiles();
|
|
370
|
+
const current = getCurrentProfile();
|
|
371
|
+
|
|
372
|
+
if (profiles.length === 0) {
|
|
373
|
+
info('No profiles found');
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
success(`${profiles.length} profile(s):\n`);
|
|
378
|
+
|
|
379
|
+
for (const p of profiles) {
|
|
380
|
+
// Temporarily switch to profile to check status
|
|
381
|
+
setProfileOverride(p);
|
|
382
|
+
const authenticated = isAuthenticated();
|
|
383
|
+
const email = authenticated ? getUserEmail() : null;
|
|
384
|
+
setProfileOverride(undefined);
|
|
385
|
+
|
|
386
|
+
const isCurrent = p === current;
|
|
387
|
+
const marker = isCurrent ? chalk.green('→') : ' ';
|
|
388
|
+
const status = authenticated ? chalk.green('authenticated') : chalk.yellow('not authenticated');
|
|
389
|
+
const emailStr = email ? chalk.gray(`(${email})`) : '';
|
|
390
|
+
const currentStr = isCurrent ? chalk.gray(' [current]') : '';
|
|
391
|
+
|
|
392
|
+
info(` ${marker} ${p}${currentStr}`);
|
|
393
|
+
info(` Status: ${status} ${emailStr}`);
|
|
394
|
+
}
|
|
395
|
+
} catch (err) {
|
|
396
|
+
error(String(err));
|
|
397
|
+
process.exit(1);
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// ============================================
|
|
402
|
+
// Helpers
|
|
403
|
+
// ============================================
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Detect MIME type from file extension (no external dependencies)
|
|
407
|
+
*/
|
|
408
|
+
function detectMimeType(filePath: string): string {
|
|
409
|
+
const ext = extname(filePath).toLowerCase();
|
|
410
|
+
const mimeTypes: Record<string, string> = {
|
|
411
|
+
'.pdf': 'application/pdf',
|
|
412
|
+
'.doc': 'application/msword',
|
|
413
|
+
'.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
414
|
+
'.xls': 'application/vnd.ms-excel',
|
|
415
|
+
'.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
416
|
+
'.ppt': 'application/vnd.ms-powerpoint',
|
|
417
|
+
'.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
418
|
+
'.txt': 'text/plain',
|
|
419
|
+
'.csv': 'text/csv',
|
|
420
|
+
'.html': 'text/html',
|
|
421
|
+
'.htm': 'text/html',
|
|
422
|
+
'.json': 'application/json',
|
|
423
|
+
'.xml': 'application/xml',
|
|
424
|
+
'.zip': 'application/zip',
|
|
425
|
+
'.gz': 'application/gzip',
|
|
426
|
+
'.tar': 'application/x-tar',
|
|
427
|
+
'.png': 'image/png',
|
|
428
|
+
'.jpg': 'image/jpeg',
|
|
429
|
+
'.jpeg': 'image/jpeg',
|
|
430
|
+
'.gif': 'image/gif',
|
|
431
|
+
'.webp': 'image/webp',
|
|
432
|
+
'.svg': 'image/svg+xml',
|
|
433
|
+
'.ico': 'image/x-icon',
|
|
434
|
+
'.mp3': 'audio/mpeg',
|
|
435
|
+
'.mp4': 'video/mp4',
|
|
436
|
+
'.mov': 'video/quicktime',
|
|
437
|
+
'.avi': 'video/x-msvideo',
|
|
438
|
+
'.ts': 'video/mp2t',
|
|
439
|
+
'.js': 'text/javascript',
|
|
440
|
+
'.css': 'text/css',
|
|
441
|
+
'.md': 'text/markdown',
|
|
442
|
+
'.sh': 'application/x-sh',
|
|
443
|
+
'.py': 'text/x-python',
|
|
444
|
+
};
|
|
445
|
+
return mimeTypes[ext] || 'application/octet-stream';
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// ============================================
|
|
449
|
+
// Messages Commands
|
|
450
|
+
// ============================================
|
|
451
|
+
const messagesCmd = program
|
|
452
|
+
.command('messages')
|
|
453
|
+
.description('Email message commands');
|
|
454
|
+
|
|
455
|
+
messagesCmd
|
|
456
|
+
.command('list')
|
|
457
|
+
.description('List messages in your mailbox')
|
|
458
|
+
.option('-n, --max <number>', 'Maximum messages to return', '10')
|
|
459
|
+
.option('-q, --query <query>', 'Gmail search query (e.g., "is:unread", "from:someone@example.com")')
|
|
460
|
+
.option('-l, --label <label>', 'Filter by label ID')
|
|
461
|
+
.action(async (opts) => {
|
|
462
|
+
try {
|
|
463
|
+
const gmail = requireAuth();
|
|
464
|
+
const result = await gmail.messages.list({
|
|
465
|
+
maxResults: parseInt(opts.max),
|
|
466
|
+
q: opts.query,
|
|
467
|
+
labelIds: opts.label ? [opts.label] : undefined,
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
if (!result.messages || result.messages.length === 0) {
|
|
471
|
+
info('No messages found');
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
success(`Found ${result.messages.length} messages:`);
|
|
476
|
+
|
|
477
|
+
// Fetch details for each message
|
|
478
|
+
const messages = await Promise.all(
|
|
479
|
+
result.messages.slice(0, parseInt(opts.max)).map(async (m) => {
|
|
480
|
+
const msg = await gmail.messages.get(m.id, 'metadata');
|
|
481
|
+
const headers = msg.payload?.headers || [];
|
|
482
|
+
const getHeader = (name: string) =>
|
|
483
|
+
headers.find(h => h.name.toLowerCase() === name.toLowerCase())?.value || '';
|
|
484
|
+
|
|
485
|
+
return {
|
|
486
|
+
id: m.id,
|
|
487
|
+
from: getHeader('From'),
|
|
488
|
+
subject: getHeader('Subject'),
|
|
489
|
+
date: getHeader('Date'),
|
|
490
|
+
snippet: msg.snippet?.substring(0, 50) + '...',
|
|
491
|
+
};
|
|
492
|
+
})
|
|
493
|
+
);
|
|
494
|
+
|
|
495
|
+
print(messages, getFormat(messagesCmd));
|
|
496
|
+
} catch (err) {
|
|
497
|
+
error(String(err));
|
|
498
|
+
process.exit(1);
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
messagesCmd
|
|
503
|
+
.command('read <messageId>')
|
|
504
|
+
.alias('get')
|
|
505
|
+
.description('Read a specific message')
|
|
506
|
+
.option('--body', 'Include full message body')
|
|
507
|
+
.option('--html', 'Show HTML body instead of plain text')
|
|
508
|
+
.option('--structure', 'Show message MIME structure (for debugging)')
|
|
509
|
+
.action(async (messageId: string, opts) => {
|
|
510
|
+
try {
|
|
511
|
+
const gmail = requireAuth();
|
|
512
|
+
const message = await gmail.messages.get(messageId);
|
|
513
|
+
|
|
514
|
+
const headers = message.payload?.headers || [];
|
|
515
|
+
const getHeader = (name: string) =>
|
|
516
|
+
headers.find(h => h.name.toLowerCase() === name.toLowerCase())?.value || '';
|
|
517
|
+
|
|
518
|
+
// Extract body from message parts
|
|
519
|
+
let body = '';
|
|
520
|
+
if (opts.body && message.payload) {
|
|
521
|
+
const targetType = opts.html ? 'text/html' : 'text/plain';
|
|
522
|
+
|
|
523
|
+
// Helper to check MIME type (handles charset params like "text/html; charset=utf-8")
|
|
524
|
+
const mimeMatches = (mimeType: string | undefined, target: string): boolean => {
|
|
525
|
+
if (!mimeType) return false;
|
|
526
|
+
const baseMime = mimeType.split(';')[0].trim().toLowerCase();
|
|
527
|
+
return baseMime === target.toLowerCase();
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
// Collect all text parts from the message structure
|
|
531
|
+
const collectTextParts = (part: typeof message.payload, results: Array<{mimeType: string, data: string}> = []): Array<{mimeType: string, data: string}> => {
|
|
532
|
+
if (part.body?.data && part.mimeType) {
|
|
533
|
+
const baseMime = part.mimeType.split(';')[0].trim().toLowerCase();
|
|
534
|
+
if (baseMime.startsWith('text/')) {
|
|
535
|
+
results.push({
|
|
536
|
+
mimeType: baseMime,
|
|
537
|
+
data: Buffer.from(part.body.data, 'base64url').toString('utf-8')
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
if (part.parts) {
|
|
542
|
+
for (const p of part.parts) {
|
|
543
|
+
collectTextParts(p, results);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return results;
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
const textParts = collectTextParts(message.payload);
|
|
550
|
+
|
|
551
|
+
// First, try to find exact target type
|
|
552
|
+
const exactMatch = textParts.find(p => p.mimeType === targetType);
|
|
553
|
+
if (exactMatch) {
|
|
554
|
+
body = exactMatch.data;
|
|
555
|
+
} else {
|
|
556
|
+
// Fallback: if looking for text/plain but only text/html exists, strip HTML
|
|
557
|
+
// Or if looking for text/html but only text/plain exists, use that
|
|
558
|
+
const altMatch = textParts.find(p => p.mimeType.startsWith('text/'));
|
|
559
|
+
if (altMatch) {
|
|
560
|
+
if (!opts.html && altMatch.mimeType === 'text/html') {
|
|
561
|
+
// Strip HTML to get readable plain text
|
|
562
|
+
body = altMatch.data
|
|
563
|
+
.replace(/<br\s*\/?>/gi, '\n')
|
|
564
|
+
.replace(/<\/p>/gi, '\n\n')
|
|
565
|
+
.replace(/<\/div>/gi, '\n')
|
|
566
|
+
.replace(/<\/li>/gi, '\n')
|
|
567
|
+
.replace(/<[^>]+>/g, '')
|
|
568
|
+
.replace(/ /g, ' ')
|
|
569
|
+
.replace(/&/g, '&')
|
|
570
|
+
.replace(/</g, '<')
|
|
571
|
+
.replace(/>/g, '>')
|
|
572
|
+
.replace(/"/g, '"')
|
|
573
|
+
.replace(/'/g, "'")
|
|
574
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
575
|
+
.trim();
|
|
576
|
+
} else {
|
|
577
|
+
body = altMatch.data;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
const output: Record<string, unknown> = {
|
|
584
|
+
id: message.id,
|
|
585
|
+
threadId: message.threadId,
|
|
586
|
+
from: getHeader('From'),
|
|
587
|
+
to: getHeader('To'),
|
|
588
|
+
subject: getHeader('Subject'),
|
|
589
|
+
date: getHeader('Date'),
|
|
590
|
+
labels: message.labelIds,
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
if (opts.structure) {
|
|
594
|
+
output.structure = gmail.messages.getMessageStructure(message);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if (opts.body) {
|
|
598
|
+
output.body = body;
|
|
599
|
+
} else if (!opts.structure) {
|
|
600
|
+
output.snippet = message.snippet;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
print(output, getFormat(messagesCmd));
|
|
604
|
+
} catch (err) {
|
|
605
|
+
error(String(err));
|
|
606
|
+
process.exit(1);
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
messagesCmd
|
|
611
|
+
.command('send')
|
|
612
|
+
.description('Send an email')
|
|
613
|
+
.requiredOption('-t, --to <email>', 'Recipient email address')
|
|
614
|
+
.requiredOption('-s, --subject <subject>', 'Email subject')
|
|
615
|
+
.requiredOption('-b, --body <body>', 'Email body')
|
|
616
|
+
.option('--cc <emails>', 'CC recipients (comma-separated)')
|
|
617
|
+
.option('--bcc <emails>', 'BCC recipients (comma-separated)')
|
|
618
|
+
.option('--html', 'Send as HTML email')
|
|
619
|
+
.option('--attachment <path>', 'Attach a file (can be specified multiple times)', (val: string, prev: string[]) => prev.concat([val]), [] as string[])
|
|
620
|
+
.action(async (opts) => {
|
|
621
|
+
try {
|
|
622
|
+
const gmail = requireAuth();
|
|
623
|
+
|
|
624
|
+
// Build attachments array from --attachment flags
|
|
625
|
+
type AttachmentEntry = { filename: string; mimeType: string; data: string };
|
|
626
|
+
const attachments: AttachmentEntry[] = [];
|
|
627
|
+
if (opts.attachment && (opts.attachment as string[]).length > 0) {
|
|
628
|
+
for (const attachPath of opts.attachment as string[]) {
|
|
629
|
+
const resolvedPath = resolve(attachPath);
|
|
630
|
+
if (!existsSync(resolvedPath)) {
|
|
631
|
+
error(`Attachment not found: ${attachPath}`);
|
|
632
|
+
process.exit(1);
|
|
633
|
+
}
|
|
634
|
+
const fileData = readFileSync(resolvedPath);
|
|
635
|
+
attachments.push({
|
|
636
|
+
filename: basename(resolvedPath),
|
|
637
|
+
mimeType: detectMimeType(resolvedPath),
|
|
638
|
+
data: fileData.toString('base64'),
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
const result = await gmail.messages.send({
|
|
644
|
+
to: opts.to,
|
|
645
|
+
subject: opts.subject,
|
|
646
|
+
body: opts.body,
|
|
647
|
+
cc: opts.cc?.split(',').map((e: string) => e.trim()),
|
|
648
|
+
bcc: opts.bcc?.split(',').map((e: string) => e.trim()),
|
|
649
|
+
isHtml: opts.html,
|
|
650
|
+
...(attachments.length > 0 ? { attachments } : {}),
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
success(`Email sent successfully!`);
|
|
654
|
+
info(`Message ID: ${result.id}`);
|
|
655
|
+
if (attachments.length > 0) {
|
|
656
|
+
info(`Attachments: ${attachments.map((a) => a.filename).join(', ')}`);
|
|
657
|
+
}
|
|
658
|
+
} catch (err) {
|
|
659
|
+
error(String(err));
|
|
660
|
+
process.exit(1);
|
|
661
|
+
}
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
messagesCmd
|
|
665
|
+
.command('trash <messageId>')
|
|
666
|
+
.description('Move a message to trash')
|
|
667
|
+
.action(async (messageId: string) => {
|
|
668
|
+
try {
|
|
669
|
+
const gmail = requireAuth();
|
|
670
|
+
await gmail.messages.trash(messageId);
|
|
671
|
+
success(`Message ${messageId} moved to trash`);
|
|
672
|
+
} catch (err) {
|
|
673
|
+
error(String(err));
|
|
674
|
+
process.exit(1);
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
messagesCmd
|
|
679
|
+
.command('delete <messageId>')
|
|
680
|
+
.description('Permanently delete a message')
|
|
681
|
+
.action(async (messageId: string) => {
|
|
682
|
+
try {
|
|
683
|
+
const gmail = requireAuth();
|
|
684
|
+
await gmail.messages.delete(messageId);
|
|
685
|
+
success(`Message ${messageId} permanently deleted`);
|
|
686
|
+
} catch (err) {
|
|
687
|
+
error(String(err));
|
|
688
|
+
process.exit(1);
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
messagesCmd
|
|
693
|
+
.command('mark-read <messageId>')
|
|
694
|
+
.description('Mark a message as read')
|
|
695
|
+
.action(async (messageId: string) => {
|
|
696
|
+
try {
|
|
697
|
+
const gmail = requireAuth();
|
|
698
|
+
await gmail.messages.markAsRead(messageId);
|
|
699
|
+
success(`Message ${messageId} marked as read`);
|
|
700
|
+
} catch (err) {
|
|
701
|
+
error(String(err));
|
|
702
|
+
process.exit(1);
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
messagesCmd
|
|
707
|
+
.command('mark-unread <messageId>')
|
|
708
|
+
.description('Mark a message as unread')
|
|
709
|
+
.action(async (messageId: string) => {
|
|
710
|
+
try {
|
|
711
|
+
const gmail = requireAuth();
|
|
712
|
+
await gmail.messages.markAsUnread(messageId);
|
|
713
|
+
success(`Message ${messageId} marked as unread`);
|
|
714
|
+
} catch (err) {
|
|
715
|
+
error(String(err));
|
|
716
|
+
process.exit(1);
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
messagesCmd
|
|
721
|
+
.command('star <messageId>')
|
|
722
|
+
.description('Star a message')
|
|
723
|
+
.action(async (messageId: string) => {
|
|
724
|
+
try {
|
|
725
|
+
const gmail = requireAuth();
|
|
726
|
+
await gmail.messages.star(messageId);
|
|
727
|
+
success(`Message ${messageId} starred`);
|
|
728
|
+
} catch (err) {
|
|
729
|
+
error(String(err));
|
|
730
|
+
process.exit(1);
|
|
731
|
+
}
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
messagesCmd
|
|
735
|
+
.command('archive <messageId>')
|
|
736
|
+
.description('Archive a message')
|
|
737
|
+
.action(async (messageId: string) => {
|
|
738
|
+
try {
|
|
739
|
+
const gmail = requireAuth();
|
|
740
|
+
await gmail.messages.archive(messageId);
|
|
741
|
+
success(`Message ${messageId} archived`);
|
|
742
|
+
} catch (err) {
|
|
743
|
+
error(String(err));
|
|
744
|
+
process.exit(1);
|
|
745
|
+
}
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
messagesCmd
|
|
749
|
+
.command('reply <messageId>')
|
|
750
|
+
.description('Reply to a message (stays in the same thread)')
|
|
751
|
+
.requiredOption('-b, --body <body>', 'Reply body (supports markdown)')
|
|
752
|
+
.option('--cc <emails>', 'CC recipients (comma-separated)')
|
|
753
|
+
.option('--html', 'Send as HTML email')
|
|
754
|
+
.option('--attachment <path>', 'Attach a file (can be specified multiple times)', (val: string, prev: string[]) => prev.concat([val]), [] as string[])
|
|
755
|
+
.action(async (messageId: string, opts) => {
|
|
756
|
+
try {
|
|
757
|
+
const gmail = requireAuth();
|
|
758
|
+
|
|
759
|
+
// Build attachments array from --attachment flags
|
|
760
|
+
type AttachmentEntry = { filename: string; mimeType: string; data: string };
|
|
761
|
+
const attachments: AttachmentEntry[] = [];
|
|
762
|
+
if (opts.attachment && (opts.attachment as string[]).length > 0) {
|
|
763
|
+
for (const attachPath of opts.attachment as string[]) {
|
|
764
|
+
const resolvedPath = resolve(attachPath);
|
|
765
|
+
if (!existsSync(resolvedPath)) {
|
|
766
|
+
error(`Attachment not found: ${attachPath}`);
|
|
767
|
+
process.exit(1);
|
|
768
|
+
}
|
|
769
|
+
const fileData = readFileSync(resolvedPath);
|
|
770
|
+
attachments.push({
|
|
771
|
+
filename: basename(resolvedPath),
|
|
772
|
+
mimeType: detectMimeType(resolvedPath),
|
|
773
|
+
data: fileData.toString('base64'),
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
const result = await gmail.messages.reply(messageId, {
|
|
779
|
+
body: opts.body,
|
|
780
|
+
cc: opts.cc?.split(',').map((e: string) => e.trim()),
|
|
781
|
+
isHtml: opts.html,
|
|
782
|
+
...(attachments.length > 0 ? { attachments } : {}),
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
success(`Reply sent!`);
|
|
786
|
+
info(`Message ID: ${result.id}`);
|
|
787
|
+
info(`Thread ID: ${result.threadId}`);
|
|
788
|
+
if (attachments.length > 0) {
|
|
789
|
+
info(`Attachments: ${attachments.map((a) => a.filename).join(', ')}`);
|
|
790
|
+
}
|
|
791
|
+
} catch (err) {
|
|
792
|
+
error(String(err));
|
|
793
|
+
process.exit(1);
|
|
794
|
+
}
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
messagesCmd
|
|
798
|
+
.command('add-label <messageId> <labelId>')
|
|
799
|
+
.description('Add a label to a message')
|
|
800
|
+
.action(async (messageId: string, labelId: string) => {
|
|
801
|
+
try {
|
|
802
|
+
const gmail = requireAuth();
|
|
803
|
+
await gmail.messages.addLabel(messageId, labelId);
|
|
804
|
+
success(`Label ${labelId} added to message ${messageId}`);
|
|
805
|
+
} catch (err) {
|
|
806
|
+
error(String(err));
|
|
807
|
+
process.exit(1);
|
|
808
|
+
}
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
messagesCmd
|
|
812
|
+
.command('remove-label <messageId> <labelId>')
|
|
813
|
+
.description('Remove a label from a message')
|
|
814
|
+
.action(async (messageId: string, labelId: string) => {
|
|
815
|
+
try {
|
|
816
|
+
const gmail = requireAuth();
|
|
817
|
+
await gmail.messages.removeLabel(messageId, labelId);
|
|
818
|
+
success(`Label ${labelId} removed from message ${messageId}`);
|
|
819
|
+
} catch (err) {
|
|
820
|
+
error(String(err));
|
|
821
|
+
process.exit(1);
|
|
822
|
+
}
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
// ============================================
|
|
826
|
+
// Labels Commands
|
|
827
|
+
// ============================================
|
|
828
|
+
const labelsCmd = program
|
|
829
|
+
.command('labels')
|
|
830
|
+
.description('Label management commands');
|
|
831
|
+
|
|
832
|
+
labelsCmd
|
|
833
|
+
.command('list')
|
|
834
|
+
.description('List all labels')
|
|
835
|
+
.action(async () => {
|
|
836
|
+
try {
|
|
837
|
+
const gmail = requireAuth();
|
|
838
|
+
const result = await gmail.labels.list();
|
|
839
|
+
|
|
840
|
+
if (!result.labels || result.labels.length === 0) {
|
|
841
|
+
info('No labels found');
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
success(`Found ${result.labels.length} labels:`);
|
|
846
|
+
|
|
847
|
+
const labels = result.labels.map(l => ({
|
|
848
|
+
id: l.id,
|
|
849
|
+
name: l.name,
|
|
850
|
+
type: l.type,
|
|
851
|
+
messagesTotal: l.messagesTotal,
|
|
852
|
+
messagesUnread: l.messagesUnread,
|
|
853
|
+
...(l.color ? { backgroundColor: l.color.backgroundColor, textColor: l.color.textColor } : {}),
|
|
854
|
+
}));
|
|
855
|
+
|
|
856
|
+
print(labels, getFormat(labelsCmd));
|
|
857
|
+
} catch (err) {
|
|
858
|
+
error(String(err));
|
|
859
|
+
process.exit(1);
|
|
860
|
+
}
|
|
861
|
+
});
|
|
862
|
+
|
|
863
|
+
labelsCmd
|
|
864
|
+
.command('create <name>')
|
|
865
|
+
.description('Create a new label')
|
|
866
|
+
.option('--bg-color <hex>', 'Background color (e.g. #16a765)')
|
|
867
|
+
.option('--text-color <hex>', 'Text color (e.g. #ffffff)')
|
|
868
|
+
.action(async (name: string, opts: { bgColor?: string; textColor?: string }) => {
|
|
869
|
+
try {
|
|
870
|
+
const gmail = requireAuth();
|
|
871
|
+
const label = await gmail.labels.create({
|
|
872
|
+
name,
|
|
873
|
+
backgroundColor: opts.bgColor,
|
|
874
|
+
textColor: opts.textColor,
|
|
875
|
+
});
|
|
876
|
+
success(`Label "${name}" created`);
|
|
877
|
+
info(`Label ID: ${label.id}`);
|
|
878
|
+
if (label.color) {
|
|
879
|
+
info(`Color: bg=${label.color.backgroundColor} text=${label.color.textColor}`);
|
|
880
|
+
}
|
|
881
|
+
} catch (err) {
|
|
882
|
+
error(String(err));
|
|
883
|
+
process.exit(1);
|
|
884
|
+
}
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
labelsCmd
|
|
888
|
+
.command('update <labelId>')
|
|
889
|
+
.description('Update a label name and/or color')
|
|
890
|
+
.option('--name <name>', 'New label name')
|
|
891
|
+
.option('--bg-color <hex>', 'Background color (e.g. #16a765)')
|
|
892
|
+
.option('--text-color <hex>', 'Text color (e.g. #ffffff)')
|
|
893
|
+
.action(async (labelId: string, opts: { name?: string; bgColor?: string; textColor?: string }) => {
|
|
894
|
+
try {
|
|
895
|
+
if (!opts.name && !opts.bgColor && !opts.textColor) {
|
|
896
|
+
error('At least one of --name, --bg-color, or --text-color is required');
|
|
897
|
+
process.exit(1);
|
|
898
|
+
}
|
|
899
|
+
const gmail = requireAuth();
|
|
900
|
+
const label = await gmail.labels.update(labelId, {
|
|
901
|
+
name: opts.name,
|
|
902
|
+
backgroundColor: opts.bgColor,
|
|
903
|
+
textColor: opts.textColor,
|
|
904
|
+
});
|
|
905
|
+
success(`Label ${labelId} updated`);
|
|
906
|
+
if (label.name) {
|
|
907
|
+
info(`Name: ${label.name}`);
|
|
908
|
+
}
|
|
909
|
+
if (label.color) {
|
|
910
|
+
info(`Color: bg=${label.color.backgroundColor} text=${label.color.textColor}`);
|
|
911
|
+
}
|
|
912
|
+
} catch (err) {
|
|
913
|
+
error(String(err));
|
|
914
|
+
process.exit(1);
|
|
915
|
+
}
|
|
916
|
+
});
|
|
917
|
+
|
|
918
|
+
labelsCmd
|
|
919
|
+
.command('rename <labelId> <newName>')
|
|
920
|
+
.description('Rename a label')
|
|
921
|
+
.action(async (labelId: string, newName: string) => {
|
|
922
|
+
try {
|
|
923
|
+
const gmail = requireAuth();
|
|
924
|
+
const label = await gmail.labels.update(labelId, { name: newName });
|
|
925
|
+
success(`Renamed to: ${label.name}`);
|
|
926
|
+
} catch (err) {
|
|
927
|
+
error(String(err));
|
|
928
|
+
process.exit(1);
|
|
929
|
+
}
|
|
930
|
+
});
|
|
931
|
+
|
|
932
|
+
labelsCmd
|
|
933
|
+
.command('delete <labelId>')
|
|
934
|
+
.description('Delete a label')
|
|
935
|
+
.action(async (labelId: string) => {
|
|
936
|
+
try {
|
|
937
|
+
const gmail = requireAuth();
|
|
938
|
+
await gmail.labels.delete(labelId);
|
|
939
|
+
success(`Label ${labelId} deleted`);
|
|
940
|
+
} catch (err) {
|
|
941
|
+
error(String(err));
|
|
942
|
+
process.exit(1);
|
|
943
|
+
}
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
// ============================================
|
|
947
|
+
// Threads Commands
|
|
948
|
+
// ============================================
|
|
949
|
+
const threadsCmd = program
|
|
950
|
+
.command('threads')
|
|
951
|
+
.description('Email thread commands');
|
|
952
|
+
|
|
953
|
+
threadsCmd
|
|
954
|
+
.command('list')
|
|
955
|
+
.description('List threads in your mailbox')
|
|
956
|
+
.option('-n, --max <number>', 'Maximum threads to return', '10')
|
|
957
|
+
.option('-q, --query <query>', 'Gmail search query')
|
|
958
|
+
.action(async (opts) => {
|
|
959
|
+
try {
|
|
960
|
+
const gmail = requireAuth();
|
|
961
|
+
const result = await gmail.threads.list({
|
|
962
|
+
maxResults: parseInt(opts.max),
|
|
963
|
+
q: opts.query,
|
|
964
|
+
});
|
|
965
|
+
|
|
966
|
+
if (!result.threads || result.threads.length === 0) {
|
|
967
|
+
info('No threads found');
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
success(`Found ${result.threads.length} threads:`);
|
|
972
|
+
print(result.threads, getFormat(threadsCmd));
|
|
973
|
+
} catch (err) {
|
|
974
|
+
error(String(err));
|
|
975
|
+
process.exit(1);
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
|
|
979
|
+
threadsCmd
|
|
980
|
+
.command('read <threadId>')
|
|
981
|
+
.description('Read a specific thread')
|
|
982
|
+
.action(async (threadId: string) => {
|
|
983
|
+
try {
|
|
984
|
+
const gmail = requireAuth();
|
|
985
|
+
const thread = await gmail.threads.get(threadId);
|
|
986
|
+
|
|
987
|
+
const output = {
|
|
988
|
+
id: thread.id,
|
|
989
|
+
messagesCount: thread.messages?.length || 0,
|
|
990
|
+
messages: thread.messages?.map(m => {
|
|
991
|
+
const headers = m.payload?.headers || [];
|
|
992
|
+
const getHeader = (name: string) =>
|
|
993
|
+
headers.find(h => h.name.toLowerCase() === name.toLowerCase())?.value || '';
|
|
994
|
+
|
|
995
|
+
return {
|
|
996
|
+
id: m.id,
|
|
997
|
+
from: getHeader('From'),
|
|
998
|
+
subject: getHeader('Subject'),
|
|
999
|
+
date: getHeader('Date'),
|
|
1000
|
+
snippet: m.snippet?.substring(0, 50) + '...',
|
|
1001
|
+
};
|
|
1002
|
+
}),
|
|
1003
|
+
};
|
|
1004
|
+
|
|
1005
|
+
print(output, getFormat(threadsCmd));
|
|
1006
|
+
} catch (err) {
|
|
1007
|
+
error(String(err));
|
|
1008
|
+
process.exit(1);
|
|
1009
|
+
}
|
|
1010
|
+
});
|
|
1011
|
+
|
|
1012
|
+
// ============================================
|
|
1013
|
+
// Drafts Commands
|
|
1014
|
+
// ============================================
|
|
1015
|
+
const draftsCmd = program
|
|
1016
|
+
.command('drafts')
|
|
1017
|
+
.description('Draft management commands');
|
|
1018
|
+
|
|
1019
|
+
draftsCmd
|
|
1020
|
+
.command('list')
|
|
1021
|
+
.description('List drafts')
|
|
1022
|
+
.option('-n, --max <number>', 'Maximum drafts to return', '10')
|
|
1023
|
+
.action(async (opts) => {
|
|
1024
|
+
try {
|
|
1025
|
+
const gmail = requireAuth();
|
|
1026
|
+
const result = await gmail.drafts.list(parseInt(opts.max));
|
|
1027
|
+
|
|
1028
|
+
if (!result.drafts || result.drafts.length === 0) {
|
|
1029
|
+
info('No drafts found');
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
success(`Found ${result.drafts.length} drafts:`);
|
|
1034
|
+
print(result.drafts, getFormat(draftsCmd));
|
|
1035
|
+
} catch (err) {
|
|
1036
|
+
error(String(err));
|
|
1037
|
+
process.exit(1);
|
|
1038
|
+
}
|
|
1039
|
+
});
|
|
1040
|
+
|
|
1041
|
+
draftsCmd
|
|
1042
|
+
.command('create')
|
|
1043
|
+
.description('Create a new draft')
|
|
1044
|
+
.requiredOption('-t, --to <email>', 'Recipient email address')
|
|
1045
|
+
.requiredOption('-s, --subject <subject>', 'Email subject')
|
|
1046
|
+
.requiredOption('-b, --body <body>', 'Email body')
|
|
1047
|
+
.option('--cc <emails>', 'CC recipients (comma-separated)')
|
|
1048
|
+
.option('--html', 'Send as HTML email')
|
|
1049
|
+
.action(async (opts) => {
|
|
1050
|
+
try {
|
|
1051
|
+
const gmail = requireAuth();
|
|
1052
|
+
const draft = await gmail.drafts.create({
|
|
1053
|
+
to: opts.to,
|
|
1054
|
+
subject: opts.subject,
|
|
1055
|
+
body: opts.body,
|
|
1056
|
+
cc: opts.cc?.split(',').map((e: string) => e.trim()),
|
|
1057
|
+
isHtml: opts.html,
|
|
1058
|
+
});
|
|
1059
|
+
|
|
1060
|
+
success(`Draft created!`);
|
|
1061
|
+
info(`Draft ID: ${draft.id}`);
|
|
1062
|
+
} catch (err) {
|
|
1063
|
+
error(String(err));
|
|
1064
|
+
process.exit(1);
|
|
1065
|
+
}
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
draftsCmd
|
|
1069
|
+
.command('send <draftId>')
|
|
1070
|
+
.description('Send a draft')
|
|
1071
|
+
.action(async (draftId: string) => {
|
|
1072
|
+
try {
|
|
1073
|
+
const gmail = requireAuth();
|
|
1074
|
+
const result = await gmail.drafts.send(draftId);
|
|
1075
|
+
success(`Draft sent!`);
|
|
1076
|
+
info(`Message ID: ${result.id}`);
|
|
1077
|
+
} catch (err) {
|
|
1078
|
+
error(String(err));
|
|
1079
|
+
process.exit(1);
|
|
1080
|
+
}
|
|
1081
|
+
});
|
|
1082
|
+
|
|
1083
|
+
draftsCmd
|
|
1084
|
+
.command('delete <draftId>')
|
|
1085
|
+
.description('Delete a draft')
|
|
1086
|
+
.action(async (draftId: string) => {
|
|
1087
|
+
try {
|
|
1088
|
+
const gmail = requireAuth();
|
|
1089
|
+
await gmail.drafts.delete(draftId);
|
|
1090
|
+
success(`Draft ${draftId} deleted`);
|
|
1091
|
+
} catch (err) {
|
|
1092
|
+
error(String(err));
|
|
1093
|
+
process.exit(1);
|
|
1094
|
+
}
|
|
1095
|
+
});
|
|
1096
|
+
|
|
1097
|
+
draftsCmd
|
|
1098
|
+
.command('update <draftId>')
|
|
1099
|
+
.description('Update an existing draft')
|
|
1100
|
+
.requiredOption('-t, --to <email>', 'Recipient email address')
|
|
1101
|
+
.requiredOption('-s, --subject <subject>', 'Email subject')
|
|
1102
|
+
.requiredOption('-b, --body <body>', 'Email body')
|
|
1103
|
+
.option('--cc <emails>', 'CC recipients (comma-separated)')
|
|
1104
|
+
.option('--html', 'Send as HTML email')
|
|
1105
|
+
.action(async (draftId: string, opts) => {
|
|
1106
|
+
try {
|
|
1107
|
+
const gmail = requireAuth();
|
|
1108
|
+
const draft = await gmail.drafts.update(draftId, {
|
|
1109
|
+
to: opts.to,
|
|
1110
|
+
subject: opts.subject,
|
|
1111
|
+
body: opts.body,
|
|
1112
|
+
cc: opts.cc?.split(',').map((e: string) => e.trim()),
|
|
1113
|
+
isHtml: opts.html,
|
|
1114
|
+
});
|
|
1115
|
+
|
|
1116
|
+
success(`Draft updated!`);
|
|
1117
|
+
info(`Draft ID: ${draft.id}`);
|
|
1118
|
+
} catch (err) {
|
|
1119
|
+
error(String(err));
|
|
1120
|
+
process.exit(1);
|
|
1121
|
+
}
|
|
1122
|
+
});
|
|
1123
|
+
|
|
1124
|
+
// ============================================
|
|
1125
|
+
// Filters Commands
|
|
1126
|
+
// ============================================
|
|
1127
|
+
const filtersCmd = program
|
|
1128
|
+
.command('filters')
|
|
1129
|
+
.description('Email filter management commands');
|
|
1130
|
+
|
|
1131
|
+
filtersCmd
|
|
1132
|
+
.command('list')
|
|
1133
|
+
.description('List all email filters')
|
|
1134
|
+
.action(async () => {
|
|
1135
|
+
try {
|
|
1136
|
+
const gmail = requireAuth();
|
|
1137
|
+
const result = await gmail.filters.list();
|
|
1138
|
+
|
|
1139
|
+
if (!result.filter || result.filter.length === 0) {
|
|
1140
|
+
info('No filters found');
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
success(`Found ${result.filter.length} filters:`);
|
|
1145
|
+
const output = result.filter.map(f => ({
|
|
1146
|
+
id: f.id,
|
|
1147
|
+
from: f.criteria?.from || '-',
|
|
1148
|
+
to: f.criteria?.to || '-',
|
|
1149
|
+
subject: f.criteria?.subject || '-',
|
|
1150
|
+
query: f.criteria?.query || '-',
|
|
1151
|
+
actions: Object.keys(f.action || {}).join(', '),
|
|
1152
|
+
}));
|
|
1153
|
+
print(output, getFormat(filtersCmd));
|
|
1154
|
+
} catch (err) {
|
|
1155
|
+
error(String(err));
|
|
1156
|
+
process.exit(1);
|
|
1157
|
+
}
|
|
1158
|
+
});
|
|
1159
|
+
|
|
1160
|
+
filtersCmd
|
|
1161
|
+
.command('get <filterId>')
|
|
1162
|
+
.description('Get details of a specific filter')
|
|
1163
|
+
.action(async (filterId: string) => {
|
|
1164
|
+
try {
|
|
1165
|
+
const gmail = requireAuth();
|
|
1166
|
+
const filter = await gmail.filters.get(filterId);
|
|
1167
|
+
print(filter, getFormat(filtersCmd));
|
|
1168
|
+
} catch (err) {
|
|
1169
|
+
error(String(err));
|
|
1170
|
+
process.exit(1);
|
|
1171
|
+
}
|
|
1172
|
+
});
|
|
1173
|
+
|
|
1174
|
+
filtersCmd
|
|
1175
|
+
.command('create')
|
|
1176
|
+
.description('Create a new filter')
|
|
1177
|
+
.option('--from <email>', 'Match emails from this address')
|
|
1178
|
+
.option('--to <email>', 'Match emails to this address')
|
|
1179
|
+
.option('--subject <text>', 'Match emails with this subject')
|
|
1180
|
+
.option('--query <query>', 'Match emails matching this Gmail search query')
|
|
1181
|
+
.option('--has-attachment', 'Match emails with attachments')
|
|
1182
|
+
.option('--add-label <labelId>', 'Add this label to matching emails')
|
|
1183
|
+
.option('--remove-label <labelId>', 'Remove this label from matching emails')
|
|
1184
|
+
.option('--archive', 'Archive matching emails')
|
|
1185
|
+
.option('--mark-read', 'Mark matching emails as read')
|
|
1186
|
+
.option('--star', 'Star matching emails')
|
|
1187
|
+
.option('--trash', 'Move matching emails to trash')
|
|
1188
|
+
.option('--important', 'Mark matching emails as important')
|
|
1189
|
+
.option('--never-spam', 'Never send matching emails to spam')
|
|
1190
|
+
.action(async (opts) => {
|
|
1191
|
+
try {
|
|
1192
|
+
// Build criteria
|
|
1193
|
+
const criteria: Record<string, unknown> = {};
|
|
1194
|
+
if (opts.from) criteria.from = opts.from;
|
|
1195
|
+
if (opts.to) criteria.to = opts.to;
|
|
1196
|
+
if (opts.subject) criteria.subject = opts.subject;
|
|
1197
|
+
if (opts.query) criteria.query = opts.query;
|
|
1198
|
+
if (opts.hasAttachment) criteria.hasAttachment = true;
|
|
1199
|
+
|
|
1200
|
+
if (Object.keys(criteria).length === 0) {
|
|
1201
|
+
error('At least one filter criteria is required (--from, --to, --subject, --query, or --has-attachment)');
|
|
1202
|
+
process.exit(1);
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
// Build action
|
|
1206
|
+
const action: Record<string, unknown> = {};
|
|
1207
|
+
if (opts.addLabel) action.addLabelIds = [opts.addLabel];
|
|
1208
|
+
if (opts.removeLabel) action.removeLabelIds = [opts.removeLabel];
|
|
1209
|
+
if (opts.archive) action.archive = true;
|
|
1210
|
+
if (opts.markRead) action.markRead = true;
|
|
1211
|
+
if (opts.star) action.star = true;
|
|
1212
|
+
if (opts.trash) action.trash = true;
|
|
1213
|
+
if (opts.important) action.markImportant = true;
|
|
1214
|
+
if (opts.neverSpam) action.neverSpam = true;
|
|
1215
|
+
|
|
1216
|
+
if (Object.keys(action).length === 0) {
|
|
1217
|
+
error('At least one filter action is required (--add-label, --archive, --mark-read, --star, --trash, --important, --never-spam)');
|
|
1218
|
+
process.exit(1);
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
const gmail = requireAuth();
|
|
1222
|
+
const filter = await gmail.filters.create({ criteria, action });
|
|
1223
|
+
|
|
1224
|
+
success(`Filter created!`);
|
|
1225
|
+
info(`Filter ID: ${filter.id}`);
|
|
1226
|
+
} catch (err) {
|
|
1227
|
+
error(String(err));
|
|
1228
|
+
process.exit(1);
|
|
1229
|
+
}
|
|
1230
|
+
});
|
|
1231
|
+
|
|
1232
|
+
filtersCmd
|
|
1233
|
+
.command('delete <filterId>')
|
|
1234
|
+
.description('Delete a filter')
|
|
1235
|
+
.action(async (filterId: string) => {
|
|
1236
|
+
try {
|
|
1237
|
+
const gmail = requireAuth();
|
|
1238
|
+
await gmail.filters.delete(filterId);
|
|
1239
|
+
success(`Filter ${filterId} deleted`);
|
|
1240
|
+
} catch (err) {
|
|
1241
|
+
error(String(err));
|
|
1242
|
+
process.exit(1);
|
|
1243
|
+
}
|
|
1244
|
+
});
|
|
1245
|
+
|
|
1246
|
+
// ============================================
|
|
1247
|
+
// Attachments Commands
|
|
1248
|
+
// ============================================
|
|
1249
|
+
const attachmentsCmd = program
|
|
1250
|
+
.command('attachments')
|
|
1251
|
+
.description('Email attachment commands');
|
|
1252
|
+
|
|
1253
|
+
attachmentsCmd
|
|
1254
|
+
.command('list <messageId>')
|
|
1255
|
+
.description('List attachments in a message')
|
|
1256
|
+
.action(async (messageId: string) => {
|
|
1257
|
+
try {
|
|
1258
|
+
const gmail = requireAuth();
|
|
1259
|
+
const attachments = await gmail.attachments.list(messageId);
|
|
1260
|
+
|
|
1261
|
+
if (attachments.length === 0) {
|
|
1262
|
+
info('No attachments found in this message');
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
success(`Found ${attachments.length} attachment(s):`);
|
|
1267
|
+
const output = attachments.map(a => ({
|
|
1268
|
+
filename: a.filename,
|
|
1269
|
+
mimeType: a.mimeType,
|
|
1270
|
+
size: `${Math.round(a.size / 1024)} KB`,
|
|
1271
|
+
attachmentId: a.attachmentId.substring(0, 20) + '...',
|
|
1272
|
+
}));
|
|
1273
|
+
print(output, getFormat(attachmentsCmd));
|
|
1274
|
+
} catch (err) {
|
|
1275
|
+
error(String(err));
|
|
1276
|
+
process.exit(1);
|
|
1277
|
+
}
|
|
1278
|
+
});
|
|
1279
|
+
|
|
1280
|
+
attachmentsCmd
|
|
1281
|
+
.command('download <messageId>')
|
|
1282
|
+
.description('Download all attachments from a message')
|
|
1283
|
+
.option('-a, --attachment-id <id>', 'Download specific attachment by ID')
|
|
1284
|
+
.option('-d, --dir <path>', 'Directory to save attachments (default: connector storage dir)')
|
|
1285
|
+
.action(async (messageId: string, opts) => {
|
|
1286
|
+
try {
|
|
1287
|
+
const gmail = requireAuth();
|
|
1288
|
+
const outputDir = opts.dir ? resolve(opts.dir) : undefined;
|
|
1289
|
+
|
|
1290
|
+
if (opts.attachmentId) {
|
|
1291
|
+
// Download specific attachment
|
|
1292
|
+
const attachments = await gmail.attachments.list(messageId);
|
|
1293
|
+
const attachment = attachments.find(a => a.attachmentId === opts.attachmentId);
|
|
1294
|
+
|
|
1295
|
+
if (!attachment) {
|
|
1296
|
+
error('Attachment not found');
|
|
1297
|
+
process.exit(1);
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
info(`Downloading ${attachment.filename}...`);
|
|
1301
|
+
const result = await gmail.attachments.download(
|
|
1302
|
+
messageId,
|
|
1303
|
+
attachment.attachmentId,
|
|
1304
|
+
attachment.filename,
|
|
1305
|
+
attachment.mimeType,
|
|
1306
|
+
outputDir
|
|
1307
|
+
);
|
|
1308
|
+
|
|
1309
|
+
success(`Downloaded: ${result.filename}`);
|
|
1310
|
+
info(`Saved to: ${result.path}`);
|
|
1311
|
+
info(`Size: ${Math.round(result.size / 1024)} KB`);
|
|
1312
|
+
} else {
|
|
1313
|
+
// Download all attachments
|
|
1314
|
+
info('Downloading all attachments...');
|
|
1315
|
+
const results = await gmail.attachments.downloadAll(messageId, outputDir);
|
|
1316
|
+
|
|
1317
|
+
if (results.length === 0) {
|
|
1318
|
+
info('No attachments found in this message');
|
|
1319
|
+
return;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
success(`Downloaded ${results.length} attachment(s):`);
|
|
1323
|
+
for (const result of results) {
|
|
1324
|
+
info(` • ${result.filename} (${Math.round(result.size / 1024)} KB)`);
|
|
1325
|
+
}
|
|
1326
|
+
const savedDir = outputDir ?? gmail.attachments.getStoragePath(messageId);
|
|
1327
|
+
info(`\nSaved to: ${savedDir}`);
|
|
1328
|
+
}
|
|
1329
|
+
} catch (err) {
|
|
1330
|
+
error(String(err));
|
|
1331
|
+
process.exit(1);
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
|
|
1335
|
+
attachmentsCmd
|
|
1336
|
+
.command('path <messageId>')
|
|
1337
|
+
.description('Show where attachments are/would be stored')
|
|
1338
|
+
.action(async (messageId: string) => {
|
|
1339
|
+
const gmail = requireAuth();
|
|
1340
|
+
const path = gmail.attachments.getStoragePath(messageId);
|
|
1341
|
+
info(`Attachments path: ${path}`);
|
|
1342
|
+
});
|
|
1343
|
+
|
|
1344
|
+
|
|
1345
|
+
attachmentsCmd
|
|
1346
|
+
.command('bulk-download <query>')
|
|
1347
|
+
.description('Bulk-download attachments from messages matching a Gmail search query')
|
|
1348
|
+
.option('-o, --output <dir>', 'Output directory', './gmail-attachments')
|
|
1349
|
+
.option('--organize-by-date', 'Organize files into subdirs by email date (YYYY/MM/)')
|
|
1350
|
+
.option('-n, --max <number>', 'Maximum messages to process', '100')
|
|
1351
|
+
.action(async (query: string, opts) => {
|
|
1352
|
+
try {
|
|
1353
|
+
const gmail = requireAuth();
|
|
1354
|
+
const outputDir = resolve(opts.output);
|
|
1355
|
+
const organizeByDate = !!opts.organizeByDate;
|
|
1356
|
+
const maxMessages = parseInt(opts.max);
|
|
1357
|
+
|
|
1358
|
+
info(`Searching for messages matching: ${chalk.cyan(query)}`);
|
|
1359
|
+
info(`Output directory: ${chalk.cyan(outputDir)}`);
|
|
1360
|
+
if (organizeByDate) info('Organizing by date: enabled');
|
|
1361
|
+
|
|
1362
|
+
// Paginate through matching messages
|
|
1363
|
+
const allMessageIds: string[] = [];
|
|
1364
|
+
let pageToken: string | undefined;
|
|
1365
|
+
|
|
1366
|
+
do {
|
|
1367
|
+
const result = await gmail.messages.list({
|
|
1368
|
+
q: query,
|
|
1369
|
+
maxResults: Math.min(maxMessages - allMessageIds.length, 500),
|
|
1370
|
+
pageToken,
|
|
1371
|
+
});
|
|
1372
|
+
|
|
1373
|
+
if (result.messages) {
|
|
1374
|
+
for (const m of result.messages) {
|
|
1375
|
+
if (m.id) allMessageIds.push(m.id);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
pageToken = result.nextPageToken;
|
|
1380
|
+
} while (pageToken && allMessageIds.length < maxMessages);
|
|
1381
|
+
|
|
1382
|
+
if (allMessageIds.length === 0) {
|
|
1383
|
+
info('No messages found matching the query.');
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
info(`Found ${allMessageIds.length} message(s). Scanning for attachments...`);
|
|
1388
|
+
|
|
1389
|
+
let totalDownloaded = 0;
|
|
1390
|
+
let totalSkipped = 0;
|
|
1391
|
+
let totalErrors = 0;
|
|
1392
|
+
|
|
1393
|
+
for (let i = 0; i < allMessageIds.length; i++) {
|
|
1394
|
+
const messageId = allMessageIds[i];
|
|
1395
|
+
const progress = `[${i + 1}/${allMessageIds.length}]`;
|
|
1396
|
+
|
|
1397
|
+
try {
|
|
1398
|
+
const attachments = await gmail.attachments.list(messageId);
|
|
1399
|
+
|
|
1400
|
+
if (attachments.length === 0) continue;
|
|
1401
|
+
|
|
1402
|
+
// Determine destination directory
|
|
1403
|
+
let destDir = outputDir;
|
|
1404
|
+
if (organizeByDate) {
|
|
1405
|
+
// Fetch minimal message metadata to get internalDate
|
|
1406
|
+
const fullMsg = await (gmail as any).client.get(
|
|
1407
|
+
`/users/me/messages/${messageId}`,
|
|
1408
|
+
{ format: 'minimal' }
|
|
1409
|
+
);
|
|
1410
|
+
const msgDate = fullMsg?.internalDate
|
|
1411
|
+
? new Date(parseInt(fullMsg.internalDate))
|
|
1412
|
+
: new Date();
|
|
1413
|
+
const year = msgDate.getFullYear().toString();
|
|
1414
|
+
const month = (msgDate.getMonth() + 1).toString().padStart(2, '0');
|
|
1415
|
+
destDir = join(outputDir, year, month);
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
if (!existsSync(destDir)) {
|
|
1419
|
+
mkdirSync(destDir, { recursive: true });
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
for (const attachment of attachments) {
|
|
1423
|
+
try {
|
|
1424
|
+
const data = await gmail.attachments.get(messageId, attachment.attachmentId);
|
|
1425
|
+
const cleanFilename = attachment.filename.replace(/[\u00A0\u2000-\u200B\u202F\u205F\u3000]/g, ' ');
|
|
1426
|
+
|
|
1427
|
+
// Avoid overwriting existing files
|
|
1428
|
+
let finalFilename = cleanFilename;
|
|
1429
|
+
let destPath = join(destDir, finalFilename);
|
|
1430
|
+
if (existsSync(destPath)) {
|
|
1431
|
+
const dotIdx = cleanFilename.lastIndexOf('.');
|
|
1432
|
+
const suffix = '_' + messageId.slice(-6);
|
|
1433
|
+
finalFilename = dotIdx !== -1
|
|
1434
|
+
? cleanFilename.slice(0, dotIdx) + suffix + cleanFilename.slice(dotIdx)
|
|
1435
|
+
: cleanFilename + suffix;
|
|
1436
|
+
destPath = join(destDir, finalFilename);
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
const buffer = Buffer.from(data.data, 'base64url');
|
|
1440
|
+
writeFileSync(destPath, buffer);
|
|
1441
|
+
|
|
1442
|
+
info(`${progress} ${chalk.green('✓')} ${finalFilename} (${(buffer.length / 1024).toFixed(1)} KB)`);
|
|
1443
|
+
totalDownloaded++;
|
|
1444
|
+
} catch (attachErr) {
|
|
1445
|
+
warn(`${progress} ${chalk.red('✗')} ${attachment.filename}: ${String(attachErr)}`);
|
|
1446
|
+
totalErrors++;
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
} catch (msgErr) {
|
|
1450
|
+
warn(`${progress} ${chalk.yellow('!')} Message ${messageId}: ${String(msgErr)}`);
|
|
1451
|
+
totalSkipped++;
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
info('');
|
|
1456
|
+
success('Bulk download complete:');
|
|
1457
|
+
info(` Downloaded: ${totalDownloaded} attachment(s)`);
|
|
1458
|
+
if (totalSkipped > 0) info(` Skipped: ${totalSkipped} message(s) with errors`);
|
|
1459
|
+
if (totalErrors > 0) info(` Failed: ${totalErrors} attachment(s)`);
|
|
1460
|
+
info(` Saved to: ${outputDir}`);
|
|
1461
|
+
} catch (err) {
|
|
1462
|
+
error(String(err));
|
|
1463
|
+
process.exit(1);
|
|
1464
|
+
}
|
|
1465
|
+
});
|
|
1466
|
+
|
|
1467
|
+
// ============================================
|
|
1468
|
+
// Search Command (shortcut)
|
|
1469
|
+
// ============================================
|
|
1470
|
+
program
|
|
1471
|
+
.command('search <query>')
|
|
1472
|
+
.description('Search messages (shortcut for "messages list -q")')
|
|
1473
|
+
.option('-n, --max <number>', 'Maximum messages to return', '10')
|
|
1474
|
+
.action(async (query: string, opts) => {
|
|
1475
|
+
try {
|
|
1476
|
+
const gmail = requireAuth();
|
|
1477
|
+
const result = await gmail.messages.list({
|
|
1478
|
+
maxResults: parseInt(opts.max),
|
|
1479
|
+
q: query,
|
|
1480
|
+
});
|
|
1481
|
+
|
|
1482
|
+
if (!result.messages || result.messages.length === 0) {
|
|
1483
|
+
info(`No messages found for query: ${query}`);
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
success(`Found ${result.messages.length} messages:`);
|
|
1488
|
+
|
|
1489
|
+
const messages = await Promise.all(
|
|
1490
|
+
result.messages.slice(0, parseInt(opts.max)).map(async (m) => {
|
|
1491
|
+
const msg = await gmail.messages.get(m.id, 'metadata');
|
|
1492
|
+
const headers = msg.payload?.headers || [];
|
|
1493
|
+
const getHeader = (name: string) =>
|
|
1494
|
+
headers.find(h => h.name.toLowerCase() === name.toLowerCase())?.value || '';
|
|
1495
|
+
|
|
1496
|
+
return {
|
|
1497
|
+
id: m.id,
|
|
1498
|
+
from: getHeader('From'),
|
|
1499
|
+
subject: getHeader('Subject'),
|
|
1500
|
+
date: getHeader('Date'),
|
|
1501
|
+
};
|
|
1502
|
+
})
|
|
1503
|
+
);
|
|
1504
|
+
|
|
1505
|
+
print(messages, getFormat(program));
|
|
1506
|
+
} catch (err) {
|
|
1507
|
+
error(String(err));
|
|
1508
|
+
process.exit(1);
|
|
1509
|
+
}
|
|
1510
|
+
});
|
|
1511
|
+
|
|
1512
|
+
// ============================================
|
|
1513
|
+
// Contacts Commands
|
|
1514
|
+
// ============================================
|
|
1515
|
+
const contactsCmd = program
|
|
1516
|
+
.command('contacts')
|
|
1517
|
+
.description('Contact management commands');
|
|
1518
|
+
|
|
1519
|
+
contactsCmd
|
|
1520
|
+
.command('list')
|
|
1521
|
+
.description('List all saved contacts')
|
|
1522
|
+
.action(() => {
|
|
1523
|
+
try {
|
|
1524
|
+
const contacts = getAllContacts();
|
|
1525
|
+
if (contacts.length === 0) {
|
|
1526
|
+
info('No contacts saved');
|
|
1527
|
+
return;
|
|
1528
|
+
}
|
|
1529
|
+
success(`Found ${contacts.length} contacts:`);
|
|
1530
|
+
const output = contacts.map(c => ({
|
|
1531
|
+
email: c.email,
|
|
1532
|
+
name: c.name || `${c.firstName || ''} ${c.lastName || ''}`.trim() || '-',
|
|
1533
|
+
company: c.company || '-',
|
|
1534
|
+
}));
|
|
1535
|
+
print(output, getFormat(contactsCmd));
|
|
1536
|
+
} catch (err) {
|
|
1537
|
+
error(String(err));
|
|
1538
|
+
process.exit(1);
|
|
1539
|
+
}
|
|
1540
|
+
});
|
|
1541
|
+
|
|
1542
|
+
contactsCmd
|
|
1543
|
+
.command('add <email>')
|
|
1544
|
+
.description('Add a new contact')
|
|
1545
|
+
.option('-n, --name <name>', 'Full name')
|
|
1546
|
+
.option('-f, --first <firstName>', 'First name')
|
|
1547
|
+
.option('-l, --last <lastName>', 'Last name')
|
|
1548
|
+
.option('-c, --company <company>', 'Company name')
|
|
1549
|
+
.option('--notes <notes>', 'Notes')
|
|
1550
|
+
.action((email: string, opts) => {
|
|
1551
|
+
try {
|
|
1552
|
+
const contact: Partial<Contact> = {
|
|
1553
|
+
email,
|
|
1554
|
+
name: opts.name,
|
|
1555
|
+
firstName: opts.first,
|
|
1556
|
+
lastName: opts.last,
|
|
1557
|
+
company: opts.company,
|
|
1558
|
+
notes: opts.notes,
|
|
1559
|
+
};
|
|
1560
|
+
saveContact(contact as Contact);
|
|
1561
|
+
success(`Contact ${email} saved!`);
|
|
1562
|
+
} catch (err) {
|
|
1563
|
+
error(String(err));
|
|
1564
|
+
process.exit(1);
|
|
1565
|
+
}
|
|
1566
|
+
});
|
|
1567
|
+
|
|
1568
|
+
contactsCmd
|
|
1569
|
+
.command('show <email>')
|
|
1570
|
+
.description('Show a contact\'s details')
|
|
1571
|
+
.action((email: string) => {
|
|
1572
|
+
try {
|
|
1573
|
+
const contact = getContact(email);
|
|
1574
|
+
if (!contact) {
|
|
1575
|
+
warn(`Contact ${email} not found`);
|
|
1576
|
+
return;
|
|
1577
|
+
}
|
|
1578
|
+
print(contact, getFormat(contactsCmd));
|
|
1579
|
+
} catch (err) {
|
|
1580
|
+
error(String(err));
|
|
1581
|
+
process.exit(1);
|
|
1582
|
+
}
|
|
1583
|
+
});
|
|
1584
|
+
|
|
1585
|
+
contactsCmd
|
|
1586
|
+
.command('delete <email>')
|
|
1587
|
+
.description('Delete a contact')
|
|
1588
|
+
.action((email: string) => {
|
|
1589
|
+
try {
|
|
1590
|
+
const deleted = deleteContact(email);
|
|
1591
|
+
if (deleted) {
|
|
1592
|
+
success(`Contact ${email} deleted`);
|
|
1593
|
+
} else {
|
|
1594
|
+
warn(`Contact ${email} not found`);
|
|
1595
|
+
}
|
|
1596
|
+
} catch (err) {
|
|
1597
|
+
error(String(err));
|
|
1598
|
+
process.exit(1);
|
|
1599
|
+
}
|
|
1600
|
+
});
|
|
1601
|
+
|
|
1602
|
+
contactsCmd
|
|
1603
|
+
.command('search <query>')
|
|
1604
|
+
.description('Search contacts by name or email')
|
|
1605
|
+
.action((query: string) => {
|
|
1606
|
+
try {
|
|
1607
|
+
const results = searchContacts(query);
|
|
1608
|
+
if (results.length === 0) {
|
|
1609
|
+
info(`No contacts found matching "${query}"`);
|
|
1610
|
+
return;
|
|
1611
|
+
}
|
|
1612
|
+
success(`Found ${results.length} contacts:`);
|
|
1613
|
+
const output = results.map(c => ({
|
|
1614
|
+
email: c.email,
|
|
1615
|
+
name: c.name || `${c.firstName || ''} ${c.lastName || ''}`.trim() || '-',
|
|
1616
|
+
company: c.company || '-',
|
|
1617
|
+
}));
|
|
1618
|
+
print(output, getFormat(contactsCmd));
|
|
1619
|
+
} catch (err) {
|
|
1620
|
+
error(String(err));
|
|
1621
|
+
process.exit(1);
|
|
1622
|
+
}
|
|
1623
|
+
});
|
|
1624
|
+
|
|
1625
|
+
contactsCmd
|
|
1626
|
+
.command('import <query>')
|
|
1627
|
+
.description('Import contacts from email search results (e.g., "from:@company.com")')
|
|
1628
|
+
.option('-n, --max <number>', 'Maximum emails to search', '50')
|
|
1629
|
+
.action(async (query: string, opts) => {
|
|
1630
|
+
try {
|
|
1631
|
+
const gmail = requireAuth();
|
|
1632
|
+
info(`Searching for emails matching: ${query}`);
|
|
1633
|
+
|
|
1634
|
+
const result = await gmail.messages.list({
|
|
1635
|
+
maxResults: parseInt(opts.max),
|
|
1636
|
+
q: query,
|
|
1637
|
+
});
|
|
1638
|
+
|
|
1639
|
+
if (!result.messages || result.messages.length === 0) {
|
|
1640
|
+
info('No messages found');
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
info(`Found ${result.messages.length} messages, extracting contacts...`);
|
|
1645
|
+
|
|
1646
|
+
// Extract unique contacts from messages
|
|
1647
|
+
const contactsMap = new Map<string, { email: string; name?: string }>();
|
|
1648
|
+
|
|
1649
|
+
for (const m of result.messages) {
|
|
1650
|
+
const msg = await gmail.messages.get(m.id, 'metadata');
|
|
1651
|
+
const headers = msg.payload?.headers || [];
|
|
1652
|
+
const fromHeader = headers.find(h => h.name.toLowerCase() === 'from')?.value || '';
|
|
1653
|
+
|
|
1654
|
+
// Parse "Name <email>" or just "email" format
|
|
1655
|
+
const match = fromHeader.match(/^(?:"?([^"<]+)"?\s*)?<?([^>]+@[^>]+)>?$/);
|
|
1656
|
+
if (match) {
|
|
1657
|
+
const name = match[1]?.trim();
|
|
1658
|
+
const email = match[2]?.trim().toLowerCase();
|
|
1659
|
+
if (email && !contactsMap.has(email)) {
|
|
1660
|
+
contactsMap.set(email, { email, name });
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
if (contactsMap.size === 0) {
|
|
1666
|
+
info('No contacts found in messages');
|
|
1667
|
+
return;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
// Save contacts
|
|
1671
|
+
let savedCount = 0;
|
|
1672
|
+
for (const contact of contactsMap.values()) {
|
|
1673
|
+
// Extract domain for company name
|
|
1674
|
+
const domain = contact.email.split('@')[1];
|
|
1675
|
+
const company = domain?.split('.')[0];
|
|
1676
|
+
|
|
1677
|
+
saveContact({
|
|
1678
|
+
email: contact.email,
|
|
1679
|
+
name: contact.name,
|
|
1680
|
+
company: company ? company.charAt(0).toUpperCase() + company.slice(1) : undefined,
|
|
1681
|
+
} as Contact);
|
|
1682
|
+
savedCount++;
|
|
1683
|
+
info(` + ${contact.name || contact.email} <${contact.email}>`);
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
success(`Imported ${savedCount} contacts!`);
|
|
1687
|
+
} catch (err) {
|
|
1688
|
+
error(String(err));
|
|
1689
|
+
process.exit(1);
|
|
1690
|
+
}
|
|
1691
|
+
});
|
|
1692
|
+
|
|
1693
|
+
contactsCmd
|
|
1694
|
+
.command('from-message <messageId>')
|
|
1695
|
+
.description('Save the sender of a specific message as a contact')
|
|
1696
|
+
.action(async (messageId: string) => {
|
|
1697
|
+
try {
|
|
1698
|
+
const gmail = requireAuth();
|
|
1699
|
+
const msg = await gmail.messages.get(messageId, 'metadata');
|
|
1700
|
+
const headers = msg.payload?.headers || [];
|
|
1701
|
+
const fromHeader = headers.find(h => h.name.toLowerCase() === 'from')?.value || '';
|
|
1702
|
+
|
|
1703
|
+
// Parse "Name <email>" or just "email" format
|
|
1704
|
+
const match = fromHeader.match(/^(?:"?([^"<]+)"?\s*)?<?([^>]+@[^>]+)>?$/);
|
|
1705
|
+
if (!match) {
|
|
1706
|
+
error('Could not parse sender from message');
|
|
1707
|
+
process.exit(1);
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
const name = match[1]?.trim();
|
|
1711
|
+
const email = match[2]?.trim().toLowerCase();
|
|
1712
|
+
const domain = email.split('@')[1];
|
|
1713
|
+
const company = domain?.split('.')[0];
|
|
1714
|
+
|
|
1715
|
+
saveContact({
|
|
1716
|
+
email,
|
|
1717
|
+
name,
|
|
1718
|
+
company: company ? company.charAt(0).toUpperCase() + company.slice(1) : undefined,
|
|
1719
|
+
} as Contact);
|
|
1720
|
+
|
|
1721
|
+
success(`Contact saved: ${name || email} <${email}>`);
|
|
1722
|
+
} catch (err) {
|
|
1723
|
+
error(String(err));
|
|
1724
|
+
process.exit(1);
|
|
1725
|
+
}
|
|
1726
|
+
});
|
|
1727
|
+
|
|
1728
|
+
// ============================================
|
|
1729
|
+
// Settings Commands
|
|
1730
|
+
// ============================================
|
|
1731
|
+
const settingsCmd = program
|
|
1732
|
+
.command('settings')
|
|
1733
|
+
.description('Manage CLI settings');
|
|
1734
|
+
|
|
1735
|
+
settingsCmd
|
|
1736
|
+
.command('show')
|
|
1737
|
+
.description('Show current settings')
|
|
1738
|
+
.action(() => {
|
|
1739
|
+
const settings = loadSettings();
|
|
1740
|
+
print(settings, getFormat(settingsCmd));
|
|
1741
|
+
});
|
|
1742
|
+
|
|
1743
|
+
settingsCmd
|
|
1744
|
+
.command('set <key> <value>')
|
|
1745
|
+
.description('Set a setting value (e.g., "markdownEnabled true")')
|
|
1746
|
+
.action((key: string, value: string) => {
|
|
1747
|
+
try {
|
|
1748
|
+
const settings = loadSettings();
|
|
1749
|
+
const validKeys = Object.keys(settings);
|
|
1750
|
+
if (!validKeys.includes(key)) {
|
|
1751
|
+
error(`Invalid setting: ${key}`);
|
|
1752
|
+
info(`Valid settings: ${validKeys.join(', ')}`);
|
|
1753
|
+
process.exit(1);
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
// Parse value based on type
|
|
1757
|
+
let parsedValue: string | boolean;
|
|
1758
|
+
if (value === 'true') parsedValue = true;
|
|
1759
|
+
else if (value === 'false') parsedValue = false;
|
|
1760
|
+
else parsedValue = value;
|
|
1761
|
+
|
|
1762
|
+
setSetting(key as keyof Settings, parsedValue as Settings[keyof Settings]);
|
|
1763
|
+
success(`Setting ${key} = ${parsedValue}`);
|
|
1764
|
+
} catch (err) {
|
|
1765
|
+
error(String(err));
|
|
1766
|
+
process.exit(1);
|
|
1767
|
+
}
|
|
1768
|
+
});
|
|
1769
|
+
|
|
1770
|
+
settingsCmd
|
|
1771
|
+
.command('set-signature <signature>')
|
|
1772
|
+
.description('Set a custom email signature')
|
|
1773
|
+
.action((signature: string) => {
|
|
1774
|
+
setSignature(signature);
|
|
1775
|
+
success('Signature saved');
|
|
1776
|
+
});
|
|
1777
|
+
|
|
1778
|
+
settingsCmd
|
|
1779
|
+
.command('sync-signature')
|
|
1780
|
+
.description('Fetch and save your Gmail signature')
|
|
1781
|
+
.action(async () => {
|
|
1782
|
+
try {
|
|
1783
|
+
const gmail = requireAuth();
|
|
1784
|
+
const signature = await gmail.profile.getSignature();
|
|
1785
|
+
if (signature) {
|
|
1786
|
+
setSignature(signature);
|
|
1787
|
+
success('Gmail signature synced!');
|
|
1788
|
+
info(`Signature: ${signature.substring(0, 50)}${signature.length > 50 ? '...' : ''}`);
|
|
1789
|
+
} else {
|
|
1790
|
+
warn('No signature found in Gmail settings');
|
|
1791
|
+
}
|
|
1792
|
+
} catch (err) {
|
|
1793
|
+
error(String(err));
|
|
1794
|
+
process.exit(1);
|
|
1795
|
+
}
|
|
1796
|
+
});
|
|
1797
|
+
|
|
1798
|
+
// ============================================
|
|
1799
|
+
// Export Commands
|
|
1800
|
+
// ============================================
|
|
1801
|
+
const exportCmd = program
|
|
1802
|
+
.command('export')
|
|
1803
|
+
.description('Export emails to EML or MBOX format');
|
|
1804
|
+
|
|
1805
|
+
exportCmd
|
|
1806
|
+
.command('messages')
|
|
1807
|
+
.description('Export messages to EML or MBOX format')
|
|
1808
|
+
.option('-q, --query <query>', 'Gmail search query')
|
|
1809
|
+
.option('-l, --label <labelId>', 'Filter by label ID')
|
|
1810
|
+
.option('-n, --max <number>', 'Maximum messages to export', '100')
|
|
1811
|
+
.option('--format <format>', 'Output format: eml or mbox', 'mbox')
|
|
1812
|
+
.option('-o, --output <dir>', 'Output directory')
|
|
1813
|
+
.option('-f, --filename <name>', 'Output filename')
|
|
1814
|
+
.action(async (opts) => {
|
|
1815
|
+
try {
|
|
1816
|
+
const gmail = requireAuth();
|
|
1817
|
+
info(`Exporting messages${opts.query ? ` matching "${opts.query}"` : ''}...`);
|
|
1818
|
+
|
|
1819
|
+
const result = await gmail.export.exportMessages({
|
|
1820
|
+
query: opts.query,
|
|
1821
|
+
labelIds: opts.label ? [opts.label] : undefined,
|
|
1822
|
+
maxResults: parseInt(opts.max),
|
|
1823
|
+
format: opts.format,
|
|
1824
|
+
outputDir: opts.output,
|
|
1825
|
+
filename: opts.filename,
|
|
1826
|
+
});
|
|
1827
|
+
|
|
1828
|
+
success(`Exported ${result.messageCount} message(s)`);
|
|
1829
|
+
info(`Format: ${result.format.toUpperCase()}`);
|
|
1830
|
+
info(`File: ${result.filePath}`);
|
|
1831
|
+
} catch (err) {
|
|
1832
|
+
error(String(err));
|
|
1833
|
+
process.exit(1);
|
|
1834
|
+
}
|
|
1835
|
+
});
|
|
1836
|
+
|
|
1837
|
+
exportCmd
|
|
1838
|
+
.command('inbox')
|
|
1839
|
+
.description('Export inbox messages')
|
|
1840
|
+
.option('-n, --max <number>', 'Maximum messages to export', '100')
|
|
1841
|
+
.option('--format <format>', 'Output format: eml or mbox', 'mbox')
|
|
1842
|
+
.option('-o, --output <dir>', 'Output directory')
|
|
1843
|
+
.option('-f, --filename <name>', 'Output filename')
|
|
1844
|
+
.action(async (opts) => {
|
|
1845
|
+
try {
|
|
1846
|
+
const gmail = requireAuth();
|
|
1847
|
+
info('Exporting inbox messages...');
|
|
1848
|
+
|
|
1849
|
+
const result = await gmail.export.exportInbox({
|
|
1850
|
+
maxResults: parseInt(opts.max),
|
|
1851
|
+
format: opts.format,
|
|
1852
|
+
outputDir: opts.output,
|
|
1853
|
+
filename: opts.filename,
|
|
1854
|
+
});
|
|
1855
|
+
|
|
1856
|
+
success(`Exported ${result.messageCount} inbox message(s)`);
|
|
1857
|
+
info(`Format: ${result.format.toUpperCase()}`);
|
|
1858
|
+
info(`File: ${result.filePath}`);
|
|
1859
|
+
} catch (err) {
|
|
1860
|
+
error(String(err));
|
|
1861
|
+
process.exit(1);
|
|
1862
|
+
}
|
|
1863
|
+
});
|
|
1864
|
+
|
|
1865
|
+
exportCmd
|
|
1866
|
+
.command('sent')
|
|
1867
|
+
.description('Export sent messages')
|
|
1868
|
+
.option('-n, --max <number>', 'Maximum messages to export', '100')
|
|
1869
|
+
.option('--format <format>', 'Output format: eml or mbox', 'mbox')
|
|
1870
|
+
.option('-o, --output <dir>', 'Output directory')
|
|
1871
|
+
.option('-f, --filename <name>', 'Output filename')
|
|
1872
|
+
.action(async (opts) => {
|
|
1873
|
+
try {
|
|
1874
|
+
const gmail = requireAuth();
|
|
1875
|
+
info('Exporting sent messages...');
|
|
1876
|
+
|
|
1877
|
+
const result = await gmail.export.exportSent({
|
|
1878
|
+
maxResults: parseInt(opts.max),
|
|
1879
|
+
format: opts.format,
|
|
1880
|
+
outputDir: opts.output,
|
|
1881
|
+
filename: opts.filename,
|
|
1882
|
+
});
|
|
1883
|
+
|
|
1884
|
+
success(`Exported ${result.messageCount} sent message(s)`);
|
|
1885
|
+
info(`Format: ${result.format.toUpperCase()}`);
|
|
1886
|
+
info(`File: ${result.filePath}`);
|
|
1887
|
+
} catch (err) {
|
|
1888
|
+
error(String(err));
|
|
1889
|
+
process.exit(1);
|
|
1890
|
+
}
|
|
1891
|
+
});
|
|
1892
|
+
|
|
1893
|
+
exportCmd
|
|
1894
|
+
.command('starred')
|
|
1895
|
+
.description('Export starred messages')
|
|
1896
|
+
.option('-n, --max <number>', 'Maximum messages to export', '100')
|
|
1897
|
+
.option('--format <format>', 'Output format: eml or mbox', 'mbox')
|
|
1898
|
+
.option('-o, --output <dir>', 'Output directory')
|
|
1899
|
+
.option('-f, --filename <name>', 'Output filename')
|
|
1900
|
+
.action(async (opts) => {
|
|
1901
|
+
try {
|
|
1902
|
+
const gmail = requireAuth();
|
|
1903
|
+
info('Exporting starred messages...');
|
|
1904
|
+
|
|
1905
|
+
const result = await gmail.export.exportStarred({
|
|
1906
|
+
maxResults: parseInt(opts.max),
|
|
1907
|
+
format: opts.format,
|
|
1908
|
+
outputDir: opts.output,
|
|
1909
|
+
filename: opts.filename,
|
|
1910
|
+
});
|
|
1911
|
+
|
|
1912
|
+
success(`Exported ${result.messageCount} starred message(s)`);
|
|
1913
|
+
info(`Format: ${result.format.toUpperCase()}`);
|
|
1914
|
+
info(`File: ${result.filePath}`);
|
|
1915
|
+
} catch (err) {
|
|
1916
|
+
error(String(err));
|
|
1917
|
+
process.exit(1);
|
|
1918
|
+
}
|
|
1919
|
+
});
|
|
1920
|
+
|
|
1921
|
+
exportCmd
|
|
1922
|
+
.command('label <labelId>')
|
|
1923
|
+
.description('Export messages from a specific label')
|
|
1924
|
+
.option('-n, --max <number>', 'Maximum messages to export', '100')
|
|
1925
|
+
.option('--format <format>', 'Output format: eml or mbox', 'mbox')
|
|
1926
|
+
.option('-o, --output <dir>', 'Output directory')
|
|
1927
|
+
.option('-f, --filename <name>', 'Output filename')
|
|
1928
|
+
.action(async (labelId: string, opts) => {
|
|
1929
|
+
try {
|
|
1930
|
+
const gmail = requireAuth();
|
|
1931
|
+
info(`Exporting messages from label "${labelId}"...`);
|
|
1932
|
+
|
|
1933
|
+
const result = await gmail.export.exportLabel(labelId, {
|
|
1934
|
+
maxResults: parseInt(opts.max),
|
|
1935
|
+
format: opts.format,
|
|
1936
|
+
outputDir: opts.output,
|
|
1937
|
+
filename: opts.filename,
|
|
1938
|
+
});
|
|
1939
|
+
|
|
1940
|
+
success(`Exported ${result.messageCount} message(s)`);
|
|
1941
|
+
info(`Format: ${result.format.toUpperCase()}`);
|
|
1942
|
+
info(`File: ${result.filePath}`);
|
|
1943
|
+
} catch (err) {
|
|
1944
|
+
error(String(err));
|
|
1945
|
+
process.exit(1);
|
|
1946
|
+
}
|
|
1947
|
+
});
|
|
1948
|
+
|
|
1949
|
+
exportCmd
|
|
1950
|
+
.command('message <messageId>')
|
|
1951
|
+
.description('Export a single message to EML format')
|
|
1952
|
+
.option('-o, --output <dir>', 'Output directory')
|
|
1953
|
+
.option('-f, --filename <name>', 'Output filename')
|
|
1954
|
+
.action(async (messageId: string, opts) => {
|
|
1955
|
+
try {
|
|
1956
|
+
const gmail = requireAuth();
|
|
1957
|
+
info(`Exporting message ${messageId}...`);
|
|
1958
|
+
|
|
1959
|
+
const result = await gmail.export.exportMessage(messageId, {
|
|
1960
|
+
outputDir: opts.output,
|
|
1961
|
+
filename: opts.filename,
|
|
1962
|
+
});
|
|
1963
|
+
|
|
1964
|
+
success(`Message exported`);
|
|
1965
|
+
info(`File: ${result.filePath}`);
|
|
1966
|
+
} catch (err) {
|
|
1967
|
+
error(String(err));
|
|
1968
|
+
process.exit(1);
|
|
1969
|
+
}
|
|
1970
|
+
});
|
|
1971
|
+
|
|
1972
|
+
exportCmd
|
|
1973
|
+
.command('thread <threadId>')
|
|
1974
|
+
.description('Export an entire thread (conversation)')
|
|
1975
|
+
.option('--format <format>', 'Output format: eml or mbox', 'mbox')
|
|
1976
|
+
.option('-o, --output <dir>', 'Output directory')
|
|
1977
|
+
.option('-f, --filename <name>', 'Output filename')
|
|
1978
|
+
.action(async (threadId: string, opts) => {
|
|
1979
|
+
try {
|
|
1980
|
+
const gmail = requireAuth();
|
|
1981
|
+
info(`Exporting thread ${threadId}...`);
|
|
1982
|
+
|
|
1983
|
+
const result = await gmail.export.exportThread(threadId, {
|
|
1984
|
+
format: opts.format,
|
|
1985
|
+
outputDir: opts.output,
|
|
1986
|
+
filename: opts.filename,
|
|
1987
|
+
});
|
|
1988
|
+
|
|
1989
|
+
success(`Exported ${result.messageCount} message(s) from thread`);
|
|
1990
|
+
info(`Format: ${result.format.toUpperCase()}`);
|
|
1991
|
+
info(`File: ${result.filePath}`);
|
|
1992
|
+
} catch (err) {
|
|
1993
|
+
error(String(err));
|
|
1994
|
+
process.exit(1);
|
|
1995
|
+
}
|
|
1996
|
+
});
|
|
1997
|
+
|
|
1998
|
+
// ============================================
|
|
1999
|
+
// Bulk Operations Commands
|
|
2000
|
+
// ============================================
|
|
2001
|
+
const bulkCmd = program
|
|
2002
|
+
.command('bulk')
|
|
2003
|
+
.description('Bulk operations on messages (using Gmail search queries)');
|
|
2004
|
+
|
|
2005
|
+
bulkCmd
|
|
2006
|
+
.command('preview <query>')
|
|
2007
|
+
.description('Preview messages matching a Gmail search query')
|
|
2008
|
+
.option('-n, --max <number>', 'Maximum messages to preview', '20')
|
|
2009
|
+
.action(async (query: string, opts) => {
|
|
2010
|
+
try {
|
|
2011
|
+
const gmail = requireAuth();
|
|
2012
|
+
info(`Searching for messages matching: ${query}`);
|
|
2013
|
+
|
|
2014
|
+
const result = await gmail.bulk.preview(query, parseInt(opts.max));
|
|
2015
|
+
|
|
2016
|
+
if (result.messages.length === 0) {
|
|
2017
|
+
info('No messages found matching the query');
|
|
2018
|
+
return;
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
success(`Found ${result.total} message(s):`);
|
|
2022
|
+
const output = result.messages.map(m => ({
|
|
2023
|
+
id: m.id,
|
|
2024
|
+
from: m.from || '-',
|
|
2025
|
+
subject: m.subject || '(no subject)',
|
|
2026
|
+
date: m.date || '-',
|
|
2027
|
+
}));
|
|
2028
|
+
print(output, getFormat(bulkCmd));
|
|
2029
|
+
} catch (err) {
|
|
2030
|
+
error(String(err));
|
|
2031
|
+
process.exit(1);
|
|
2032
|
+
}
|
|
2033
|
+
});
|
|
2034
|
+
|
|
2035
|
+
bulkCmd
|
|
2036
|
+
.command('label <query>')
|
|
2037
|
+
.description('Add or remove labels from messages matching a query')
|
|
2038
|
+
.option('-a, --add <labels>', 'Labels to add (comma-separated names or IDs)')
|
|
2039
|
+
.option('-r, --remove <labels>', 'Labels to remove (comma-separated names or IDs)')
|
|
2040
|
+
.option('-n, --max <number>', 'Maximum messages to process', '100')
|
|
2041
|
+
.option('--all', 'Process all matching messages (paginates through entire result set)')
|
|
2042
|
+
.option('--offset <number>', 'Skip first N results before processing', '0')
|
|
2043
|
+
.option('--skip-labeled', 'Skip messages that already have the target label(s) applied')
|
|
2044
|
+
.option('--dry-run', 'Preview changes without applying them')
|
|
2045
|
+
.option('--batch', 'Use Gmail batch API for faster processing (recommended for large batches)')
|
|
2046
|
+
.action(async (query: string, opts) => {
|
|
2047
|
+
try {
|
|
2048
|
+
if (!opts.add && !opts.remove) {
|
|
2049
|
+
error('At least one of --add or --remove is required');
|
|
2050
|
+
process.exit(1);
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
const gmail = requireAuth();
|
|
2054
|
+
const addLabels = opts.add ? opts.add.split(',').map((l: string) => l.trim()) : [];
|
|
2055
|
+
const removeLabels = opts.remove ? opts.remove.split(',').map((l: string) => l.trim()) : [];
|
|
2056
|
+
const maxResults = opts.all ? Infinity : parseInt(opts.max);
|
|
2057
|
+
const offset = parseInt(opts.offset) || 0;
|
|
2058
|
+
const skipIfLabeled = opts.skipLabeled === true;
|
|
2059
|
+
|
|
2060
|
+
info(`${opts.dryRun ? '[DRY RUN] ' : ''}Modifying labels for messages matching: ${query}`);
|
|
2061
|
+
if (addLabels.length > 0) info(` Adding: ${addLabels.join(', ')}`);
|
|
2062
|
+
if (removeLabels.length > 0) info(` Removing: ${removeLabels.join(', ')}`);
|
|
2063
|
+
if (opts.all) info(` Mode: process ALL matching messages`);
|
|
2064
|
+
if (offset > 0) info(` Offset: skipping first ${offset} results`);
|
|
2065
|
+
if (skipIfLabeled) info(` Skipping already-labeled messages`);
|
|
2066
|
+
|
|
2067
|
+
let result;
|
|
2068
|
+
if (opts.batch) {
|
|
2069
|
+
result = await gmail.bulk.batchModifyLabels({
|
|
2070
|
+
query,
|
|
2071
|
+
maxResults,
|
|
2072
|
+
addLabels,
|
|
2073
|
+
removeLabels,
|
|
2074
|
+
dryRun: opts.dryRun,
|
|
2075
|
+
skipIfLabeled,
|
|
2076
|
+
offset,
|
|
2077
|
+
});
|
|
2078
|
+
} else {
|
|
2079
|
+
result = await gmail.bulk.modifyLabels({
|
|
2080
|
+
query,
|
|
2081
|
+
maxResults,
|
|
2082
|
+
addLabels,
|
|
2083
|
+
removeLabels,
|
|
2084
|
+
dryRun: opts.dryRun,
|
|
2085
|
+
skipIfLabeled,
|
|
2086
|
+
offset,
|
|
2087
|
+
onProgress: (current, total) => {
|
|
2088
|
+
process.stdout.write(`\r Progress: ${current}/${total}`);
|
|
2089
|
+
},
|
|
2090
|
+
});
|
|
2091
|
+
console.log(); // New line after progress
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
success(`${opts.dryRun ? '[DRY RUN] ' : ''}Bulk label modification complete:`);
|
|
2095
|
+
info(` Total: ${result.total}`);
|
|
2096
|
+
info(` Success: ${result.success}`);
|
|
2097
|
+
if (result.skipped > 0) info(` Skipped (already labeled): ${result.skipped}`);
|
|
2098
|
+
if (result.failed > 0) {
|
|
2099
|
+
warn(` Failed: ${result.failed}`);
|
|
2100
|
+
for (const err of result.errors.slice(0, 5)) {
|
|
2101
|
+
info(` - ${err.messageId}: ${err.error}`);
|
|
2102
|
+
}
|
|
2103
|
+
if (result.errors.length > 5) {
|
|
2104
|
+
info(` ... and ${result.errors.length - 5} more errors`);
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
} catch (err) {
|
|
2108
|
+
error(String(err));
|
|
2109
|
+
process.exit(1);
|
|
2110
|
+
}
|
|
2111
|
+
});
|
|
2112
|
+
|
|
2113
|
+
bulkCmd
|
|
2114
|
+
.command('archive <query>')
|
|
2115
|
+
.description('Archive messages matching a query (remove from INBOX)')
|
|
2116
|
+
.option('-n, --max <number>', 'Maximum messages to process', '100')
|
|
2117
|
+
.option('--dry-run', 'Preview changes without applying them')
|
|
2118
|
+
.option('--batch', 'Use Gmail batch API for faster processing')
|
|
2119
|
+
.action(async (query: string, opts) => {
|
|
2120
|
+
try {
|
|
2121
|
+
const gmail = requireAuth();
|
|
2122
|
+
info(`${opts.dryRun ? '[DRY RUN] ' : ''}Archiving messages matching: ${query}`);
|
|
2123
|
+
|
|
2124
|
+
let result;
|
|
2125
|
+
if (opts.batch) {
|
|
2126
|
+
result = await gmail.bulk.batchModifyLabels({
|
|
2127
|
+
query,
|
|
2128
|
+
maxResults: parseInt(opts.max),
|
|
2129
|
+
removeLabelIds: ['INBOX'],
|
|
2130
|
+
dryRun: opts.dryRun,
|
|
2131
|
+
});
|
|
2132
|
+
} else {
|
|
2133
|
+
result = await gmail.bulk.archive({
|
|
2134
|
+
query,
|
|
2135
|
+
maxResults: parseInt(opts.max),
|
|
2136
|
+
dryRun: opts.dryRun,
|
|
2137
|
+
onProgress: (current, total) => {
|
|
2138
|
+
process.stdout.write(`\r Progress: ${current}/${total}`);
|
|
2139
|
+
},
|
|
2140
|
+
});
|
|
2141
|
+
console.log();
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
success(`${opts.dryRun ? '[DRY RUN] ' : ''}Bulk archive complete:`);
|
|
2145
|
+
info(` Total: ${result.total}`);
|
|
2146
|
+
info(` Success: ${result.success}`);
|
|
2147
|
+
if (result.failed > 0) warn(` Failed: ${result.failed}`);
|
|
2148
|
+
} catch (err) {
|
|
2149
|
+
error(String(err));
|
|
2150
|
+
process.exit(1);
|
|
2151
|
+
}
|
|
2152
|
+
});
|
|
2153
|
+
|
|
2154
|
+
bulkCmd
|
|
2155
|
+
.command('trash <query>')
|
|
2156
|
+
.description('Move messages matching a query to trash')
|
|
2157
|
+
.option('-n, --max <number>', 'Maximum messages to process', '100')
|
|
2158
|
+
.option('--dry-run', 'Preview changes without applying them')
|
|
2159
|
+
.action(async (query: string, opts) => {
|
|
2160
|
+
try {
|
|
2161
|
+
const gmail = requireAuth();
|
|
2162
|
+
info(`${opts.dryRun ? '[DRY RUN] ' : ''}Moving to trash messages matching: ${query}`);
|
|
2163
|
+
|
|
2164
|
+
const result = await gmail.bulk.trash({
|
|
2165
|
+
query,
|
|
2166
|
+
maxResults: parseInt(opts.max),
|
|
2167
|
+
dryRun: opts.dryRun,
|
|
2168
|
+
onProgress: (current, total) => {
|
|
2169
|
+
process.stdout.write(`\r Progress: ${current}/${total}`);
|
|
2170
|
+
},
|
|
2171
|
+
});
|
|
2172
|
+
console.log();
|
|
2173
|
+
|
|
2174
|
+
success(`${opts.dryRun ? '[DRY RUN] ' : ''}Bulk trash complete:`);
|
|
2175
|
+
info(` Total: ${result.total}`);
|
|
2176
|
+
info(` Success: ${result.success}`);
|
|
2177
|
+
if (result.failed > 0) warn(` Failed: ${result.failed}`);
|
|
2178
|
+
} catch (err) {
|
|
2179
|
+
error(String(err));
|
|
2180
|
+
process.exit(1);
|
|
2181
|
+
}
|
|
2182
|
+
});
|
|
2183
|
+
|
|
2184
|
+
bulkCmd
|
|
2185
|
+
.command('delete <query>')
|
|
2186
|
+
.description('Permanently delete messages matching a query (DANGER!)')
|
|
2187
|
+
.option('-n, --max <number>', 'Maximum messages to process', '100')
|
|
2188
|
+
.option('--dry-run', 'Preview changes without applying them')
|
|
2189
|
+
.option('--batch', 'Use Gmail batch API for faster processing')
|
|
2190
|
+
.option('--confirm', 'Confirm permanent deletion')
|
|
2191
|
+
.action(async (query: string, opts) => {
|
|
2192
|
+
try {
|
|
2193
|
+
if (!opts.dryRun && !opts.confirm) {
|
|
2194
|
+
error('Permanent deletion requires --confirm flag');
|
|
2195
|
+
info('Use --dry-run to preview what would be deleted');
|
|
2196
|
+
process.exit(1);
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
const gmail = requireAuth();
|
|
2200
|
+
warn(`${opts.dryRun ? '[DRY RUN] ' : ''}PERMANENTLY DELETING messages matching: ${query}`);
|
|
2201
|
+
|
|
2202
|
+
let result;
|
|
2203
|
+
if (opts.batch) {
|
|
2204
|
+
result = await gmail.bulk.batchDelete({
|
|
2205
|
+
query,
|
|
2206
|
+
maxResults: parseInt(opts.max),
|
|
2207
|
+
dryRun: opts.dryRun,
|
|
2208
|
+
});
|
|
2209
|
+
} else {
|
|
2210
|
+
result = await gmail.bulk.delete({
|
|
2211
|
+
query,
|
|
2212
|
+
maxResults: parseInt(opts.max),
|
|
2213
|
+
dryRun: opts.dryRun,
|
|
2214
|
+
onProgress: (current, total) => {
|
|
2215
|
+
process.stdout.write(`\r Progress: ${current}/${total}`);
|
|
2216
|
+
},
|
|
2217
|
+
});
|
|
2218
|
+
console.log();
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2221
|
+
success(`${opts.dryRun ? '[DRY RUN] ' : ''}Bulk delete complete:`);
|
|
2222
|
+
info(` Total: ${result.total}`);
|
|
2223
|
+
info(` Success: ${result.success}`);
|
|
2224
|
+
if (result.failed > 0) warn(` Failed: ${result.failed}`);
|
|
2225
|
+
} catch (err) {
|
|
2226
|
+
error(String(err));
|
|
2227
|
+
process.exit(1);
|
|
2228
|
+
}
|
|
2229
|
+
});
|
|
2230
|
+
|
|
2231
|
+
bulkCmd
|
|
2232
|
+
.command('mark-read <query>')
|
|
2233
|
+
.description('Mark messages matching a query as read')
|
|
2234
|
+
.option('-n, --max <number>', 'Maximum messages to process', '100')
|
|
2235
|
+
.option('--dry-run', 'Preview changes without applying them')
|
|
2236
|
+
.option('--batch', 'Use Gmail batch API for faster processing')
|
|
2237
|
+
.action(async (query: string, opts) => {
|
|
2238
|
+
try {
|
|
2239
|
+
const gmail = requireAuth();
|
|
2240
|
+
info(`${opts.dryRun ? '[DRY RUN] ' : ''}Marking as read messages matching: ${query}`);
|
|
2241
|
+
|
|
2242
|
+
let result;
|
|
2243
|
+
if (opts.batch) {
|
|
2244
|
+
result = await gmail.bulk.batchModifyLabels({
|
|
2245
|
+
query,
|
|
2246
|
+
maxResults: parseInt(opts.max),
|
|
2247
|
+
removeLabelIds: ['UNREAD'],
|
|
2248
|
+
dryRun: opts.dryRun,
|
|
2249
|
+
});
|
|
2250
|
+
} else {
|
|
2251
|
+
result = await gmail.bulk.markAsRead({
|
|
2252
|
+
query,
|
|
2253
|
+
maxResults: parseInt(opts.max),
|
|
2254
|
+
dryRun: opts.dryRun,
|
|
2255
|
+
onProgress: (current, total) => {
|
|
2256
|
+
process.stdout.write(`\r Progress: ${current}/${total}`);
|
|
2257
|
+
},
|
|
2258
|
+
});
|
|
2259
|
+
console.log();
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
success(`${opts.dryRun ? '[DRY RUN] ' : ''}Bulk mark-read complete:`);
|
|
2263
|
+
info(` Total: ${result.total}`);
|
|
2264
|
+
info(` Success: ${result.success}`);
|
|
2265
|
+
if (result.failed > 0) warn(` Failed: ${result.failed}`);
|
|
2266
|
+
} catch (err) {
|
|
2267
|
+
error(String(err));
|
|
2268
|
+
process.exit(1);
|
|
2269
|
+
}
|
|
2270
|
+
});
|
|
2271
|
+
|
|
2272
|
+
bulkCmd
|
|
2273
|
+
.command('mark-unread <query>')
|
|
2274
|
+
.description('Mark messages matching a query as unread')
|
|
2275
|
+
.option('-n, --max <number>', 'Maximum messages to process', '100')
|
|
2276
|
+
.option('--dry-run', 'Preview changes without applying them')
|
|
2277
|
+
.option('--batch', 'Use Gmail batch API for faster processing')
|
|
2278
|
+
.action(async (query: string, opts) => {
|
|
2279
|
+
try {
|
|
2280
|
+
const gmail = requireAuth();
|
|
2281
|
+
info(`${opts.dryRun ? '[DRY RUN] ' : ''}Marking as unread messages matching: ${query}`);
|
|
2282
|
+
|
|
2283
|
+
let result;
|
|
2284
|
+
if (opts.batch) {
|
|
2285
|
+
result = await gmail.bulk.batchModifyLabels({
|
|
2286
|
+
query,
|
|
2287
|
+
maxResults: parseInt(opts.max),
|
|
2288
|
+
addLabelIds: ['UNREAD'],
|
|
2289
|
+
dryRun: opts.dryRun,
|
|
2290
|
+
});
|
|
2291
|
+
} else {
|
|
2292
|
+
result = await gmail.bulk.markAsUnread({
|
|
2293
|
+
query,
|
|
2294
|
+
maxResults: parseInt(opts.max),
|
|
2295
|
+
dryRun: opts.dryRun,
|
|
2296
|
+
onProgress: (current, total) => {
|
|
2297
|
+
process.stdout.write(`\r Progress: ${current}/${total}`);
|
|
2298
|
+
},
|
|
2299
|
+
});
|
|
2300
|
+
console.log();
|
|
2301
|
+
}
|
|
2302
|
+
|
|
2303
|
+
success(`${opts.dryRun ? '[DRY RUN] ' : ''}Bulk mark-unread complete:`);
|
|
2304
|
+
info(` Total: ${result.total}`);
|
|
2305
|
+
info(` Success: ${result.success}`);
|
|
2306
|
+
if (result.failed > 0) warn(` Failed: ${result.failed}`);
|
|
2307
|
+
} catch (err) {
|
|
2308
|
+
error(String(err));
|
|
2309
|
+
process.exit(1);
|
|
2310
|
+
}
|
|
2311
|
+
});
|
|
2312
|
+
|
|
2313
|
+
bulkCmd
|
|
2314
|
+
.command('star <query>')
|
|
2315
|
+
.description('Star messages matching a query')
|
|
2316
|
+
.option('-n, --max <number>', 'Maximum messages to process', '100')
|
|
2317
|
+
.option('--dry-run', 'Preview changes without applying them')
|
|
2318
|
+
.option('--batch', 'Use Gmail batch API for faster processing')
|
|
2319
|
+
.action(async (query: string, opts) => {
|
|
2320
|
+
try {
|
|
2321
|
+
const gmail = requireAuth();
|
|
2322
|
+
info(`${opts.dryRun ? '[DRY RUN] ' : ''}Starring messages matching: ${query}`);
|
|
2323
|
+
|
|
2324
|
+
let result;
|
|
2325
|
+
if (opts.batch) {
|
|
2326
|
+
result = await gmail.bulk.batchModifyLabels({
|
|
2327
|
+
query,
|
|
2328
|
+
maxResults: parseInt(opts.max),
|
|
2329
|
+
addLabelIds: ['STARRED'],
|
|
2330
|
+
dryRun: opts.dryRun,
|
|
2331
|
+
});
|
|
2332
|
+
} else {
|
|
2333
|
+
result = await gmail.bulk.star({
|
|
2334
|
+
query,
|
|
2335
|
+
maxResults: parseInt(opts.max),
|
|
2336
|
+
dryRun: opts.dryRun,
|
|
2337
|
+
onProgress: (current, total) => {
|
|
2338
|
+
process.stdout.write(`\r Progress: ${current}/${total}`);
|
|
2339
|
+
},
|
|
2340
|
+
});
|
|
2341
|
+
console.log();
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2344
|
+
success(`${opts.dryRun ? '[DRY RUN] ' : ''}Bulk star complete:`);
|
|
2345
|
+
info(` Total: ${result.total}`);
|
|
2346
|
+
info(` Success: ${result.success}`);
|
|
2347
|
+
if (result.failed > 0) warn(` Failed: ${result.failed}`);
|
|
2348
|
+
} catch (err) {
|
|
2349
|
+
error(String(err));
|
|
2350
|
+
process.exit(1);
|
|
2351
|
+
}
|
|
2352
|
+
});
|
|
2353
|
+
|
|
2354
|
+
bulkCmd
|
|
2355
|
+
.command('unstar <query>')
|
|
2356
|
+
.description('Remove stars from messages matching a query')
|
|
2357
|
+
.option('-n, --max <number>', 'Maximum messages to process', '100')
|
|
2358
|
+
.option('--dry-run', 'Preview changes without applying them')
|
|
2359
|
+
.option('--batch', 'Use Gmail batch API for faster processing')
|
|
2360
|
+
.action(async (query: string, opts) => {
|
|
2361
|
+
try {
|
|
2362
|
+
const gmail = requireAuth();
|
|
2363
|
+
info(`${opts.dryRun ? '[DRY RUN] ' : ''}Removing stars from messages matching: ${query}`);
|
|
2364
|
+
|
|
2365
|
+
let result;
|
|
2366
|
+
if (opts.batch) {
|
|
2367
|
+
result = await gmail.bulk.batchModifyLabels({
|
|
2368
|
+
query,
|
|
2369
|
+
maxResults: parseInt(opts.max),
|
|
2370
|
+
removeLabelIds: ['STARRED'],
|
|
2371
|
+
dryRun: opts.dryRun,
|
|
2372
|
+
});
|
|
2373
|
+
} else {
|
|
2374
|
+
result = await gmail.bulk.unstar({
|
|
2375
|
+
query,
|
|
2376
|
+
maxResults: parseInt(opts.max),
|
|
2377
|
+
dryRun: opts.dryRun,
|
|
2378
|
+
onProgress: (current, total) => {
|
|
2379
|
+
process.stdout.write(`\r Progress: ${current}/${total}`);
|
|
2380
|
+
},
|
|
2381
|
+
});
|
|
2382
|
+
console.log();
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2385
|
+
success(`${opts.dryRun ? '[DRY RUN] ' : ''}Bulk unstar complete:`);
|
|
2386
|
+
info(` Total: ${result.total}`);
|
|
2387
|
+
info(` Success: ${result.success}`);
|
|
2388
|
+
if (result.failed > 0) warn(` Failed: ${result.failed}`);
|
|
2389
|
+
} catch (err) {
|
|
2390
|
+
error(String(err));
|
|
2391
|
+
process.exit(1);
|
|
2392
|
+
}
|
|
2393
|
+
});
|
|
2394
|
+
|
|
2395
|
+
bulkCmd
|
|
2396
|
+
.command('help-query')
|
|
2397
|
+
.description('Show Gmail search query syntax examples')
|
|
2398
|
+
.action(() => {
|
|
2399
|
+
info(chalk.bold('\nGmail Search Query Syntax:\n'));
|
|
2400
|
+
|
|
2401
|
+
info(chalk.cyan('Basic filters:'));
|
|
2402
|
+
info(' from:user@example.com - Messages from a specific sender');
|
|
2403
|
+
info(' to:user@example.com - Messages to a specific recipient');
|
|
2404
|
+
info(' subject:invoice - Messages with "invoice" in subject');
|
|
2405
|
+
info(' "exact phrase" - Messages containing exact phrase\n');
|
|
2406
|
+
|
|
2407
|
+
info(chalk.cyan('Date filters:'));
|
|
2408
|
+
info(' after:2024/01/01 - Messages after a date');
|
|
2409
|
+
info(' before:2024/12/31 - Messages before a date');
|
|
2410
|
+
info(' older_than:7d - Messages older than 7 days');
|
|
2411
|
+
info(' newer_than:1m - Messages newer than 1 month\n');
|
|
2412
|
+
|
|
2413
|
+
info(chalk.cyan('Label filters:'));
|
|
2414
|
+
info(' label:work - Messages with a specific label');
|
|
2415
|
+
info(' in:inbox - Messages in inbox');
|
|
2416
|
+
info(' in:sent - Messages in sent');
|
|
2417
|
+
info(' in:trash - Messages in trash');
|
|
2418
|
+
info(' in:spam - Messages in spam\n');
|
|
2419
|
+
|
|
2420
|
+
info(chalk.cyan('Status filters:'));
|
|
2421
|
+
info(' is:unread - Unread messages');
|
|
2422
|
+
info(' is:read - Read messages');
|
|
2423
|
+
info(' is:starred - Starred messages');
|
|
2424
|
+
info(' is:important - Important messages');
|
|
2425
|
+
info(' has:attachment - Messages with attachments\n');
|
|
2426
|
+
|
|
2427
|
+
info(chalk.cyan('Size filters:'));
|
|
2428
|
+
info(' larger:10M - Messages larger than 10MB');
|
|
2429
|
+
info(' smaller:1K - Messages smaller than 1KB\n');
|
|
2430
|
+
|
|
2431
|
+
info(chalk.cyan('Combining filters:'));
|
|
2432
|
+
info(' from:boss@company.com is:unread');
|
|
2433
|
+
info(' subject:report after:2024/01/01 before:2024/06/01');
|
|
2434
|
+
info(' from:@newsletter.com older_than:30d');
|
|
2435
|
+
info(' {from:alice@ex.com from:bob@ex.com} - OR operator');
|
|
2436
|
+
info(' -from:spam@ex.com - NOT operator (exclude)\n');
|
|
2437
|
+
|
|
2438
|
+
info(chalk.cyan('Examples:'));
|
|
2439
|
+
info(' bulk preview "from:newsletter@company.com older_than:30d"');
|
|
2440
|
+
info(' bulk archive "from:@notifications.com is:read"');
|
|
2441
|
+
info(' bulk trash "subject:unsubscribe older_than:90d" --dry-run');
|
|
2442
|
+
info(' bulk label "from:@client.com" --add "Work/Clients"');
|
|
2443
|
+
info(' bulk mark-read "is:unread older_than:7d" --batch');
|
|
2444
|
+
});
|
|
2445
|
+
|
|
2446
|
+
// Parse and execute
|
|
2447
|
+
program.parse();
|