@hasna/connectors 0.9.3 → 1.0.0

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.
Files changed (596) hide show
  1. package/bin/index.js +239 -1
  2. package/bin/mcp.js +239 -1
  3. package/bin/serve.js +238 -0
  4. package/connectors/connect-focuster/.env.example +11 -0
  5. package/connectors/connect-focuster/CLAUDE.md +272 -0
  6. package/connectors/connect-focuster/README.md +193 -0
  7. package/connectors/connect-focuster/package.json +49 -0
  8. package/connectors/connect-focuster/src/api/client.ts +213 -0
  9. package/connectors/connect-focuster/src/api/example.ts +48 -0
  10. package/connectors/connect-focuster/src/api/index.ts +51 -0
  11. package/connectors/connect-focuster/src/cli/index.ts +254 -0
  12. package/connectors/connect-focuster/src/index.ts +103 -0
  13. package/connectors/connect-focuster/src/types/index.ts +237 -0
  14. package/connectors/connect-focuster/src/utils/auth.ts +274 -0
  15. package/connectors/connect-focuster/src/utils/bulk.ts +212 -0
  16. package/connectors/connect-focuster/src/utils/config.ts +326 -0
  17. package/connectors/connect-focuster/src/utils/output.ts +175 -0
  18. package/connectors/connect-focuster/src/utils/settings.ts +114 -0
  19. package/connectors/connect-focuster/src/utils/storage.ts +198 -0
  20. package/connectors/connect-focuster/tsconfig.json +16 -0
  21. package/connectors/connect-formcarry/.env.example +11 -0
  22. package/connectors/connect-formcarry/CLAUDE.md +272 -0
  23. package/connectors/connect-formcarry/README.md +193 -0
  24. package/connectors/connect-formcarry/package.json +49 -0
  25. package/connectors/connect-formcarry/src/api/client.ts +213 -0
  26. package/connectors/connect-formcarry/src/api/example.ts +48 -0
  27. package/connectors/connect-formcarry/src/api/index.ts +51 -0
  28. package/connectors/connect-formcarry/src/cli/index.ts +254 -0
  29. package/connectors/connect-formcarry/src/index.ts +103 -0
  30. package/connectors/connect-formcarry/src/types/index.ts +237 -0
  31. package/connectors/connect-formcarry/src/utils/auth.ts +274 -0
  32. package/connectors/connect-formcarry/src/utils/bulk.ts +212 -0
  33. package/connectors/connect-formcarry/src/utils/config.ts +326 -0
  34. package/connectors/connect-formcarry/src/utils/output.ts +175 -0
  35. package/connectors/connect-formcarry/src/utils/settings.ts +114 -0
  36. package/connectors/connect-formcarry/src/utils/storage.ts +198 -0
  37. package/connectors/connect-formcarry/tsconfig.json +16 -0
  38. package/connectors/connect-formdesk/.env.example +11 -0
  39. package/connectors/connect-formdesk/CLAUDE.md +272 -0
  40. package/connectors/connect-formdesk/README.md +193 -0
  41. package/connectors/connect-formdesk/package.json +49 -0
  42. package/connectors/connect-formdesk/src/api/client.ts +213 -0
  43. package/connectors/connect-formdesk/src/api/example.ts +48 -0
  44. package/connectors/connect-formdesk/src/api/index.ts +51 -0
  45. package/connectors/connect-formdesk/src/cli/index.ts +254 -0
  46. package/connectors/connect-formdesk/src/index.ts +103 -0
  47. package/connectors/connect-formdesk/src/types/index.ts +237 -0
  48. package/connectors/connect-formdesk/src/utils/auth.ts +274 -0
  49. package/connectors/connect-formdesk/src/utils/bulk.ts +212 -0
  50. package/connectors/connect-formdesk/src/utils/config.ts +326 -0
  51. package/connectors/connect-formdesk/src/utils/output.ts +175 -0
  52. package/connectors/connect-formdesk/src/utils/settings.ts +114 -0
  53. package/connectors/connect-formdesk/src/utils/storage.ts +198 -0
  54. package/connectors/connect-formdesk/tsconfig.json +16 -0
  55. package/connectors/connect-formsite/.env.example +11 -0
  56. package/connectors/connect-formsite/CLAUDE.md +272 -0
  57. package/connectors/connect-formsite/README.md +193 -0
  58. package/connectors/connect-formsite/package.json +49 -0
  59. package/connectors/connect-formsite/src/api/client.ts +213 -0
  60. package/connectors/connect-formsite/src/api/example.ts +48 -0
  61. package/connectors/connect-formsite/src/api/index.ts +51 -0
  62. package/connectors/connect-formsite/src/cli/index.ts +254 -0
  63. package/connectors/connect-formsite/src/index.ts +103 -0
  64. package/connectors/connect-formsite/src/types/index.ts +237 -0
  65. package/connectors/connect-formsite/src/utils/auth.ts +274 -0
  66. package/connectors/connect-formsite/src/utils/bulk.ts +212 -0
  67. package/connectors/connect-formsite/src/utils/config.ts +326 -0
  68. package/connectors/connect-formsite/src/utils/output.ts +175 -0
  69. package/connectors/connect-formsite/src/utils/settings.ts +114 -0
  70. package/connectors/connect-formsite/src/utils/storage.ts +198 -0
  71. package/connectors/connect-formsite/tsconfig.json +16 -0
  72. package/connectors/connect-formsonfire/.env.example +11 -0
  73. package/connectors/connect-formsonfire/CLAUDE.md +272 -0
  74. package/connectors/connect-formsonfire/README.md +193 -0
  75. package/connectors/connect-formsonfire/package.json +49 -0
  76. package/connectors/connect-formsonfire/src/api/client.ts +213 -0
  77. package/connectors/connect-formsonfire/src/api/example.ts +48 -0
  78. package/connectors/connect-formsonfire/src/api/index.ts +51 -0
  79. package/connectors/connect-formsonfire/src/cli/index.ts +254 -0
  80. package/connectors/connect-formsonfire/src/index.ts +103 -0
  81. package/connectors/connect-formsonfire/src/types/index.ts +237 -0
  82. package/connectors/connect-formsonfire/src/utils/auth.ts +274 -0
  83. package/connectors/connect-formsonfire/src/utils/bulk.ts +212 -0
  84. package/connectors/connect-formsonfire/src/utils/config.ts +326 -0
  85. package/connectors/connect-formsonfire/src/utils/output.ts +175 -0
  86. package/connectors/connect-formsonfire/src/utils/settings.ts +114 -0
  87. package/connectors/connect-formsonfire/src/utils/storage.ts +198 -0
  88. package/connectors/connect-formsonfire/tsconfig.json +16 -0
  89. package/connectors/connect-formstackdocuments/.env.example +11 -0
  90. package/connectors/connect-formstackdocuments/CLAUDE.md +272 -0
  91. package/connectors/connect-formstackdocuments/README.md +193 -0
  92. package/connectors/connect-formstackdocuments/package.json +49 -0
  93. package/connectors/connect-formstackdocuments/src/api/client.ts +213 -0
  94. package/connectors/connect-formstackdocuments/src/api/example.ts +48 -0
  95. package/connectors/connect-formstackdocuments/src/api/index.ts +51 -0
  96. package/connectors/connect-formstackdocuments/src/cli/index.ts +254 -0
  97. package/connectors/connect-formstackdocuments/src/index.ts +103 -0
  98. package/connectors/connect-formstackdocuments/src/types/index.ts +237 -0
  99. package/connectors/connect-formstackdocuments/src/utils/auth.ts +274 -0
  100. package/connectors/connect-formstackdocuments/src/utils/bulk.ts +212 -0
  101. package/connectors/connect-formstackdocuments/src/utils/config.ts +326 -0
  102. package/connectors/connect-formstackdocuments/src/utils/output.ts +175 -0
  103. package/connectors/connect-formstackdocuments/src/utils/settings.ts +114 -0
  104. package/connectors/connect-formstackdocuments/src/utils/storage.ts +198 -0
  105. package/connectors/connect-formstackdocuments/tsconfig.json +16 -0
  106. package/connectors/connect-fortinetfortigate/.env.example +11 -0
  107. package/connectors/connect-fortinetfortigate/CLAUDE.md +272 -0
  108. package/connectors/connect-fortinetfortigate/README.md +193 -0
  109. package/connectors/connect-fortinetfortigate/package.json +49 -0
  110. package/connectors/connect-fortinetfortigate/src/api/client.ts +213 -0
  111. package/connectors/connect-fortinetfortigate/src/api/example.ts +48 -0
  112. package/connectors/connect-fortinetfortigate/src/api/index.ts +51 -0
  113. package/connectors/connect-fortinetfortigate/src/cli/index.ts +254 -0
  114. package/connectors/connect-fortinetfortigate/src/index.ts +103 -0
  115. package/connectors/connect-fortinetfortigate/src/types/index.ts +237 -0
  116. package/connectors/connect-fortinetfortigate/src/utils/auth.ts +274 -0
  117. package/connectors/connect-fortinetfortigate/src/utils/bulk.ts +212 -0
  118. package/connectors/connect-fortinetfortigate/src/utils/config.ts +326 -0
  119. package/connectors/connect-fortinetfortigate/src/utils/output.ts +175 -0
  120. package/connectors/connect-fortinetfortigate/src/utils/settings.ts +114 -0
  121. package/connectors/connect-fortinetfortigate/src/utils/storage.ts +198 -0
  122. package/connectors/connect-fortinetfortigate/tsconfig.json +16 -0
  123. package/connectors/connect-foursquare/.env.example +11 -0
  124. package/connectors/connect-foursquare/CLAUDE.md +272 -0
  125. package/connectors/connect-foursquare/README.md +193 -0
  126. package/connectors/connect-foursquare/package.json +49 -0
  127. package/connectors/connect-foursquare/src/api/client.ts +213 -0
  128. package/connectors/connect-foursquare/src/api/example.ts +48 -0
  129. package/connectors/connect-foursquare/src/api/index.ts +51 -0
  130. package/connectors/connect-foursquare/src/cli/index.ts +254 -0
  131. package/connectors/connect-foursquare/src/index.ts +103 -0
  132. package/connectors/connect-foursquare/src/types/index.ts +237 -0
  133. package/connectors/connect-foursquare/src/utils/auth.ts +274 -0
  134. package/connectors/connect-foursquare/src/utils/bulk.ts +212 -0
  135. package/connectors/connect-foursquare/src/utils/config.ts +326 -0
  136. package/connectors/connect-foursquare/src/utils/output.ts +175 -0
  137. package/connectors/connect-foursquare/src/utils/settings.ts +114 -0
  138. package/connectors/connect-foursquare/src/utils/storage.ts +198 -0
  139. package/connectors/connect-foursquare/tsconfig.json +16 -0
  140. package/connectors/connect-freedictionary/.env.example +11 -0
  141. package/connectors/connect-freedictionary/CLAUDE.md +272 -0
  142. package/connectors/connect-freedictionary/README.md +193 -0
  143. package/connectors/connect-freedictionary/package.json +49 -0
  144. package/connectors/connect-freedictionary/src/api/client.ts +213 -0
  145. package/connectors/connect-freedictionary/src/api/example.ts +48 -0
  146. package/connectors/connect-freedictionary/src/api/index.ts +51 -0
  147. package/connectors/connect-freedictionary/src/cli/index.ts +254 -0
  148. package/connectors/connect-freedictionary/src/index.ts +103 -0
  149. package/connectors/connect-freedictionary/src/types/index.ts +237 -0
  150. package/connectors/connect-freedictionary/src/utils/auth.ts +274 -0
  151. package/connectors/connect-freedictionary/src/utils/bulk.ts +212 -0
  152. package/connectors/connect-freedictionary/src/utils/config.ts +326 -0
  153. package/connectors/connect-freedictionary/src/utils/output.ts +175 -0
  154. package/connectors/connect-freedictionary/src/utils/settings.ts +114 -0
  155. package/connectors/connect-freedictionary/src/utils/storage.ts +198 -0
  156. package/connectors/connect-freedictionary/tsconfig.json +16 -0
  157. package/connectors/connect-freshping/.env.example +11 -0
  158. package/connectors/connect-freshping/CLAUDE.md +272 -0
  159. package/connectors/connect-freshping/README.md +193 -0
  160. package/connectors/connect-freshping/package.json +49 -0
  161. package/connectors/connect-freshping/src/api/client.ts +213 -0
  162. package/connectors/connect-freshping/src/api/example.ts +48 -0
  163. package/connectors/connect-freshping/src/api/index.ts +51 -0
  164. package/connectors/connect-freshping/src/cli/index.ts +254 -0
  165. package/connectors/connect-freshping/src/index.ts +103 -0
  166. package/connectors/connect-freshping/src/types/index.ts +237 -0
  167. package/connectors/connect-freshping/src/utils/auth.ts +274 -0
  168. package/connectors/connect-freshping/src/utils/bulk.ts +212 -0
  169. package/connectors/connect-freshping/src/utils/config.ts +326 -0
  170. package/connectors/connect-freshping/src/utils/output.ts +175 -0
  171. package/connectors/connect-freshping/src/utils/settings.ts +114 -0
  172. package/connectors/connect-freshping/src/utils/storage.ts +198 -0
  173. package/connectors/connect-freshping/tsconfig.json +16 -0
  174. package/connectors/connect-freshservice/.env.example +11 -0
  175. package/connectors/connect-freshservice/CLAUDE.md +272 -0
  176. package/connectors/connect-freshservice/README.md +193 -0
  177. package/connectors/connect-freshservice/package.json +51 -0
  178. package/connectors/connect-freshservice/scripts/release.ts +179 -0
  179. package/connectors/connect-freshservice/src/api/client.ts +213 -0
  180. package/connectors/connect-freshservice/src/api/example.ts +48 -0
  181. package/connectors/connect-freshservice/src/api/index.ts +51 -0
  182. package/connectors/connect-freshservice/src/cli/index.ts +254 -0
  183. package/connectors/connect-freshservice/src/index.ts +103 -0
  184. package/connectors/connect-freshservice/src/types/index.ts +237 -0
  185. package/connectors/connect-freshservice/src/utils/auth.ts +274 -0
  186. package/connectors/connect-freshservice/src/utils/bulk.ts +212 -0
  187. package/connectors/connect-freshservice/src/utils/config.ts +326 -0
  188. package/connectors/connect-freshservice/src/utils/output.ts +175 -0
  189. package/connectors/connect-freshservice/src/utils/settings.ts +114 -0
  190. package/connectors/connect-freshservice/src/utils/storage.ts +198 -0
  191. package/connectors/connect-freshservice/tsconfig.json +16 -0
  192. package/connectors/connect-freshworkscrm/.env.example +11 -0
  193. package/connectors/connect-freshworkscrm/CLAUDE.md +272 -0
  194. package/connectors/connect-freshworkscrm/README.md +193 -0
  195. package/connectors/connect-freshworkscrm/package.json +51 -0
  196. package/connectors/connect-freshworkscrm/scripts/release.ts +179 -0
  197. package/connectors/connect-freshworkscrm/src/api/client.ts +213 -0
  198. package/connectors/connect-freshworkscrm/src/api/example.ts +48 -0
  199. package/connectors/connect-freshworkscrm/src/api/index.ts +51 -0
  200. package/connectors/connect-freshworkscrm/src/cli/index.ts +254 -0
  201. package/connectors/connect-freshworkscrm/src/index.ts +103 -0
  202. package/connectors/connect-freshworkscrm/src/types/index.ts +237 -0
  203. package/connectors/connect-freshworkscrm/src/utils/auth.ts +274 -0
  204. package/connectors/connect-freshworkscrm/src/utils/bulk.ts +212 -0
  205. package/connectors/connect-freshworkscrm/src/utils/config.ts +326 -0
  206. package/connectors/connect-freshworkscrm/src/utils/output.ts +175 -0
  207. package/connectors/connect-freshworkscrm/src/utils/settings.ts +114 -0
  208. package/connectors/connect-freshworkscrm/src/utils/storage.ts +198 -0
  209. package/connectors/connect-freshworkscrm/tsconfig.json +16 -0
  210. package/connectors/connect-fullcontact/.env.example +11 -0
  211. package/connectors/connect-fullcontact/CLAUDE.md +272 -0
  212. package/connectors/connect-fullcontact/README.md +193 -0
  213. package/connectors/connect-fullcontact/package.json +51 -0
  214. package/connectors/connect-fullcontact/scripts/release.ts +179 -0
  215. package/connectors/connect-fullcontact/src/api/client.ts +213 -0
  216. package/connectors/connect-fullcontact/src/api/example.ts +48 -0
  217. package/connectors/connect-fullcontact/src/api/index.ts +51 -0
  218. package/connectors/connect-fullcontact/src/cli/index.ts +254 -0
  219. package/connectors/connect-fullcontact/src/index.ts +103 -0
  220. package/connectors/connect-fullcontact/src/types/index.ts +237 -0
  221. package/connectors/connect-fullcontact/src/utils/auth.ts +274 -0
  222. package/connectors/connect-fullcontact/src/utils/bulk.ts +212 -0
  223. package/connectors/connect-fullcontact/src/utils/config.ts +326 -0
  224. package/connectors/connect-fullcontact/src/utils/output.ts +175 -0
  225. package/connectors/connect-fullcontact/src/utils/settings.ts +114 -0
  226. package/connectors/connect-fullcontact/src/utils/storage.ts +198 -0
  227. package/connectors/connect-fullcontact/tsconfig.json +16 -0
  228. package/connectors/connect-fusioo/.env.example +11 -0
  229. package/connectors/connect-fusioo/CLAUDE.md +272 -0
  230. package/connectors/connect-fusioo/README.md +193 -0
  231. package/connectors/connect-fusioo/package.json +51 -0
  232. package/connectors/connect-fusioo/scripts/release.ts +179 -0
  233. package/connectors/connect-fusioo/src/api/client.ts +213 -0
  234. package/connectors/connect-fusioo/src/api/example.ts +48 -0
  235. package/connectors/connect-fusioo/src/api/index.ts +51 -0
  236. package/connectors/connect-fusioo/src/cli/index.ts +254 -0
  237. package/connectors/connect-fusioo/src/index.ts +103 -0
  238. package/connectors/connect-fusioo/src/types/index.ts +237 -0
  239. package/connectors/connect-fusioo/src/utils/auth.ts +274 -0
  240. package/connectors/connect-fusioo/src/utils/bulk.ts +212 -0
  241. package/connectors/connect-fusioo/src/utils/config.ts +326 -0
  242. package/connectors/connect-fusioo/src/utils/output.ts +175 -0
  243. package/connectors/connect-fusioo/src/utils/settings.ts +114 -0
  244. package/connectors/connect-fusioo/src/utils/storage.ts +198 -0
  245. package/connectors/connect-fusioo/tsconfig.json +16 -0
  246. package/connectors/connect-gali/.env.example +11 -0
  247. package/connectors/connect-gali/CLAUDE.md +272 -0
  248. package/connectors/connect-gali/README.md +193 -0
  249. package/connectors/connect-gali/package.json +51 -0
  250. package/connectors/connect-gali/scripts/release.ts +179 -0
  251. package/connectors/connect-gali/src/api/client.ts +213 -0
  252. package/connectors/connect-gali/src/api/example.ts +48 -0
  253. package/connectors/connect-gali/src/api/index.ts +51 -0
  254. package/connectors/connect-gali/src/cli/index.ts +254 -0
  255. package/connectors/connect-gali/src/index.ts +103 -0
  256. package/connectors/connect-gali/src/types/index.ts +237 -0
  257. package/connectors/connect-gali/src/utils/auth.ts +274 -0
  258. package/connectors/connect-gali/src/utils/bulk.ts +212 -0
  259. package/connectors/connect-gali/src/utils/config.ts +326 -0
  260. package/connectors/connect-gali/src/utils/output.ts +175 -0
  261. package/connectors/connect-gali/src/utils/settings.ts +114 -0
  262. package/connectors/connect-gali/src/utils/storage.ts +198 -0
  263. package/connectors/connect-gali/tsconfig.json +16 -0
  264. package/connectors/connect-gatekeeper/.env.example +11 -0
  265. package/connectors/connect-gatekeeper/CLAUDE.md +272 -0
  266. package/connectors/connect-gatekeeper/README.md +193 -0
  267. package/connectors/connect-gatekeeper/package.json +51 -0
  268. package/connectors/connect-gatekeeper/scripts/release.ts +179 -0
  269. package/connectors/connect-gatekeeper/src/api/client.ts +213 -0
  270. package/connectors/connect-gatekeeper/src/api/example.ts +48 -0
  271. package/connectors/connect-gatekeeper/src/api/index.ts +51 -0
  272. package/connectors/connect-gatekeeper/src/cli/index.ts +254 -0
  273. package/connectors/connect-gatekeeper/src/index.ts +103 -0
  274. package/connectors/connect-gatekeeper/src/types/index.ts +237 -0
  275. package/connectors/connect-gatekeeper/src/utils/auth.ts +274 -0
  276. package/connectors/connect-gatekeeper/src/utils/bulk.ts +212 -0
  277. package/connectors/connect-gatekeeper/src/utils/config.ts +326 -0
  278. package/connectors/connect-gatekeeper/src/utils/output.ts +175 -0
  279. package/connectors/connect-gatekeeper/src/utils/settings.ts +114 -0
  280. package/connectors/connect-gatekeeper/src/utils/storage.ts +198 -0
  281. package/connectors/connect-gatekeeper/tsconfig.json +16 -0
  282. package/connectors/connect-genderapi/.env.example +11 -0
  283. package/connectors/connect-genderapi/CLAUDE.md +272 -0
  284. package/connectors/connect-genderapi/README.md +193 -0
  285. package/connectors/connect-genderapi/package.json +51 -0
  286. package/connectors/connect-genderapi/scripts/release.ts +179 -0
  287. package/connectors/connect-genderapi/src/api/client.ts +213 -0
  288. package/connectors/connect-genderapi/src/api/example.ts +48 -0
  289. package/connectors/connect-genderapi/src/api/index.ts +51 -0
  290. package/connectors/connect-genderapi/src/cli/index.ts +254 -0
  291. package/connectors/connect-genderapi/src/index.ts +103 -0
  292. package/connectors/connect-genderapi/src/types/index.ts +237 -0
  293. package/connectors/connect-genderapi/src/utils/auth.ts +274 -0
  294. package/connectors/connect-genderapi/src/utils/bulk.ts +212 -0
  295. package/connectors/connect-genderapi/src/utils/config.ts +326 -0
  296. package/connectors/connect-genderapi/src/utils/output.ts +175 -0
  297. package/connectors/connect-genderapi/src/utils/settings.ts +114 -0
  298. package/connectors/connect-genderapi/src/utils/storage.ts +198 -0
  299. package/connectors/connect-genderapi/tsconfig.json +16 -0
  300. package/connectors/connect-getresponse/.env.example +11 -0
  301. package/connectors/connect-getresponse/CLAUDE.md +272 -0
  302. package/connectors/connect-getresponse/README.md +193 -0
  303. package/connectors/connect-getresponse/package.json +51 -0
  304. package/connectors/connect-getresponse/scripts/release.ts +179 -0
  305. package/connectors/connect-getresponse/src/api/client.ts +213 -0
  306. package/connectors/connect-getresponse/src/api/example.ts +48 -0
  307. package/connectors/connect-getresponse/src/api/index.ts +51 -0
  308. package/connectors/connect-getresponse/src/cli/index.ts +254 -0
  309. package/connectors/connect-getresponse/src/index.ts +103 -0
  310. package/connectors/connect-getresponse/src/types/index.ts +237 -0
  311. package/connectors/connect-getresponse/src/utils/auth.ts +274 -0
  312. package/connectors/connect-getresponse/src/utils/bulk.ts +212 -0
  313. package/connectors/connect-getresponse/src/utils/config.ts +326 -0
  314. package/connectors/connect-getresponse/src/utils/output.ts +175 -0
  315. package/connectors/connect-getresponse/src/utils/settings.ts +114 -0
  316. package/connectors/connect-getresponse/src/utils/storage.ts +198 -0
  317. package/connectors/connect-getresponse/tsconfig.json +16 -0
  318. package/connectors/connect-getscreenshot/.env.example +11 -0
  319. package/connectors/connect-getscreenshot/CLAUDE.md +272 -0
  320. package/connectors/connect-getscreenshot/README.md +193 -0
  321. package/connectors/connect-getscreenshot/package.json +51 -0
  322. package/connectors/connect-getscreenshot/scripts/release.ts +179 -0
  323. package/connectors/connect-getscreenshot/src/api/client.ts +213 -0
  324. package/connectors/connect-getscreenshot/src/api/example.ts +48 -0
  325. package/connectors/connect-getscreenshot/src/api/index.ts +51 -0
  326. package/connectors/connect-getscreenshot/src/cli/index.ts +254 -0
  327. package/connectors/connect-getscreenshot/src/index.ts +103 -0
  328. package/connectors/connect-getscreenshot/src/types/index.ts +237 -0
  329. package/connectors/connect-getscreenshot/src/utils/auth.ts +274 -0
  330. package/connectors/connect-getscreenshot/src/utils/bulk.ts +212 -0
  331. package/connectors/connect-getscreenshot/src/utils/config.ts +326 -0
  332. package/connectors/connect-getscreenshot/src/utils/output.ts +175 -0
  333. package/connectors/connect-getscreenshot/src/utils/settings.ts +114 -0
  334. package/connectors/connect-getscreenshot/src/utils/storage.ts +198 -0
  335. package/connectors/connect-getscreenshot/tsconfig.json +16 -0
  336. package/connectors/connect-ghost/.env.example +11 -0
  337. package/connectors/connect-ghost/CLAUDE.md +272 -0
  338. package/connectors/connect-ghost/README.md +193 -0
  339. package/connectors/connect-ghost/package.json +51 -0
  340. package/connectors/connect-ghost/scripts/release.ts +179 -0
  341. package/connectors/connect-ghost/src/api/client.ts +213 -0
  342. package/connectors/connect-ghost/src/api/example.ts +48 -0
  343. package/connectors/connect-ghost/src/api/index.ts +51 -0
  344. package/connectors/connect-ghost/src/cli/index.ts +254 -0
  345. package/connectors/connect-ghost/src/index.ts +103 -0
  346. package/connectors/connect-ghost/src/types/index.ts +237 -0
  347. package/connectors/connect-ghost/src/utils/auth.ts +274 -0
  348. package/connectors/connect-ghost/src/utils/bulk.ts +212 -0
  349. package/connectors/connect-ghost/src/utils/config.ts +326 -0
  350. package/connectors/connect-ghost/src/utils/output.ts +175 -0
  351. package/connectors/connect-ghost/src/utils/settings.ts +114 -0
  352. package/connectors/connect-ghost/src/utils/storage.ts +198 -0
  353. package/connectors/connect-ghost/tsconfig.json +16 -0
  354. package/connectors/connect-gitea/.env.example +11 -0
  355. package/connectors/connect-gitea/CLAUDE.md +272 -0
  356. package/connectors/connect-gitea/README.md +39 -0
  357. package/connectors/connect-gitea/package.json +49 -0
  358. package/connectors/connect-gitea/src/api/client.ts +213 -0
  359. package/connectors/connect-gitea/src/api/example.ts +48 -0
  360. package/connectors/connect-gitea/src/api/index.ts +51 -0
  361. package/connectors/connect-gitea/src/cli/index.ts +254 -0
  362. package/connectors/connect-gitea/src/index.ts +103 -0
  363. package/connectors/connect-gitea/src/types/index.ts +237 -0
  364. package/connectors/connect-gitea/src/utils/auth.ts +274 -0
  365. package/connectors/connect-gitea/src/utils/bulk.ts +212 -0
  366. package/connectors/connect-gitea/src/utils/config.ts +326 -0
  367. package/connectors/connect-gitea/src/utils/output.ts +175 -0
  368. package/connectors/connect-gitea/src/utils/settings.ts +114 -0
  369. package/connectors/connect-gitea/src/utils/storage.ts +198 -0
  370. package/connectors/connect-gitea/tsconfig.json +16 -0
  371. package/connectors/connect-gleap/.env.example +11 -0
  372. package/connectors/connect-gleap/CLAUDE.md +272 -0
  373. package/connectors/connect-gleap/README.md +39 -0
  374. package/connectors/connect-gleap/package.json +49 -0
  375. package/connectors/connect-gleap/src/api/client.ts +213 -0
  376. package/connectors/connect-gleap/src/api/example.ts +48 -0
  377. package/connectors/connect-gleap/src/api/index.ts +51 -0
  378. package/connectors/connect-gleap/src/cli/index.ts +254 -0
  379. package/connectors/connect-gleap/src/index.ts +103 -0
  380. package/connectors/connect-gleap/src/types/index.ts +237 -0
  381. package/connectors/connect-gleap/src/utils/auth.ts +274 -0
  382. package/connectors/connect-gleap/src/utils/bulk.ts +212 -0
  383. package/connectors/connect-gleap/src/utils/config.ts +326 -0
  384. package/connectors/connect-gleap/src/utils/output.ts +175 -0
  385. package/connectors/connect-gleap/src/utils/settings.ts +114 -0
  386. package/connectors/connect-gleap/src/utils/storage.ts +198 -0
  387. package/connectors/connect-gleap/tsconfig.json +16 -0
  388. package/connectors/connect-gocanvas/.env.example +11 -0
  389. package/connectors/connect-gocanvas/CLAUDE.md +272 -0
  390. package/connectors/connect-gocanvas/README.md +39 -0
  391. package/connectors/connect-gocanvas/package.json +49 -0
  392. package/connectors/connect-gocanvas/src/api/client.ts +213 -0
  393. package/connectors/connect-gocanvas/src/api/example.ts +48 -0
  394. package/connectors/connect-gocanvas/src/api/index.ts +51 -0
  395. package/connectors/connect-gocanvas/src/cli/index.ts +254 -0
  396. package/connectors/connect-gocanvas/src/index.ts +103 -0
  397. package/connectors/connect-gocanvas/src/types/index.ts +237 -0
  398. package/connectors/connect-gocanvas/src/utils/auth.ts +274 -0
  399. package/connectors/connect-gocanvas/src/utils/bulk.ts +212 -0
  400. package/connectors/connect-gocanvas/src/utils/config.ts +326 -0
  401. package/connectors/connect-gocanvas/src/utils/output.ts +175 -0
  402. package/connectors/connect-gocanvas/src/utils/settings.ts +114 -0
  403. package/connectors/connect-gocanvas/src/utils/storage.ts +198 -0
  404. package/connectors/connect-gocanvas/tsconfig.json +16 -0
  405. package/connectors/connect-godaddy/.env.example +11 -0
  406. package/connectors/connect-godaddy/CLAUDE.md +272 -0
  407. package/connectors/connect-godaddy/README.md +39 -0
  408. package/connectors/connect-godaddy/package.json +49 -0
  409. package/connectors/connect-godaddy/src/api/client.ts +213 -0
  410. package/connectors/connect-godaddy/src/api/example.ts +48 -0
  411. package/connectors/connect-godaddy/src/api/index.ts +51 -0
  412. package/connectors/connect-godaddy/src/cli/index.ts +254 -0
  413. package/connectors/connect-godaddy/src/index.ts +103 -0
  414. package/connectors/connect-godaddy/src/types/index.ts +237 -0
  415. package/connectors/connect-godaddy/src/utils/auth.ts +274 -0
  416. package/connectors/connect-godaddy/src/utils/bulk.ts +212 -0
  417. package/connectors/connect-godaddy/src/utils/config.ts +326 -0
  418. package/connectors/connect-godaddy/src/utils/output.ts +175 -0
  419. package/connectors/connect-godaddy/src/utils/settings.ts +114 -0
  420. package/connectors/connect-godaddy/src/utils/storage.ts +198 -0
  421. package/connectors/connect-godaddy/tsconfig.json +16 -0
  422. package/connectors/connect-gong/.env.example +11 -0
  423. package/connectors/connect-gong/CLAUDE.md +272 -0
  424. package/connectors/connect-gong/README.md +39 -0
  425. package/connectors/connect-gong/package.json +49 -0
  426. package/connectors/connect-gong/src/api/client.ts +213 -0
  427. package/connectors/connect-gong/src/api/example.ts +48 -0
  428. package/connectors/connect-gong/src/api/index.ts +51 -0
  429. package/connectors/connect-gong/src/cli/index.ts +254 -0
  430. package/connectors/connect-gong/src/index.ts +103 -0
  431. package/connectors/connect-gong/src/types/index.ts +237 -0
  432. package/connectors/connect-gong/src/utils/auth.ts +274 -0
  433. package/connectors/connect-gong/src/utils/bulk.ts +212 -0
  434. package/connectors/connect-gong/src/utils/config.ts +326 -0
  435. package/connectors/connect-gong/src/utils/output.ts +175 -0
  436. package/connectors/connect-gong/src/utils/settings.ts +114 -0
  437. package/connectors/connect-gong/src/utils/storage.ts +198 -0
  438. package/connectors/connect-gong/tsconfig.json +16 -0
  439. package/connectors/connect-googleads/CLAUDE.md +55 -0
  440. package/connectors/connect-googleads/README.md +39 -0
  441. package/connectors/connect-googleads/package.json +52 -0
  442. package/connectors/connect-googleads/src/api/adGroups.ts +170 -0
  443. package/connectors/connect-googleads/src/api/ads.ts +171 -0
  444. package/connectors/connect-googleads/src/api/campaigns.ts +252 -0
  445. package/connectors/connect-googleads/src/api/client.ts +214 -0
  446. package/connectors/connect-googleads/src/api/index.ts +76 -0
  447. package/connectors/connect-googleads/src/api/keywords.ts +308 -0
  448. package/connectors/connect-googleads/src/api/reports.ts +430 -0
  449. package/connectors/connect-googleads/src/cli/index.ts +1259 -0
  450. package/connectors/connect-googleads/src/index.ts +40 -0
  451. package/connectors/connect-googleads/src/types/index.ts +433 -0
  452. package/connectors/connect-googleads/src/utils/auth.ts +208 -0
  453. package/connectors/connect-googleads/src/utils/config.ts +342 -0
  454. package/connectors/connect-googleads/src/utils/output.ts +62 -0
  455. package/connectors/connect-googleads/tsconfig.json +16 -0
  456. package/connectors/connect-googleanalytics/.env.example +11 -0
  457. package/connectors/connect-googleanalytics/CLAUDE.md +272 -0
  458. package/connectors/connect-googleanalytics/README.md +39 -0
  459. package/connectors/connect-googleanalytics/package.json +49 -0
  460. package/connectors/connect-googleanalytics/src/api/client.ts +213 -0
  461. package/connectors/connect-googleanalytics/src/api/example.ts +48 -0
  462. package/connectors/connect-googleanalytics/src/api/index.ts +51 -0
  463. package/connectors/connect-googleanalytics/src/cli/index.ts +254 -0
  464. package/connectors/connect-googleanalytics/src/index.ts +103 -0
  465. package/connectors/connect-googleanalytics/src/types/index.ts +237 -0
  466. package/connectors/connect-googleanalytics/src/utils/auth.ts +274 -0
  467. package/connectors/connect-googleanalytics/src/utils/bulk.ts +212 -0
  468. package/connectors/connect-googleanalytics/src/utils/config.ts +326 -0
  469. package/connectors/connect-googleanalytics/src/utils/output.ts +175 -0
  470. package/connectors/connect-googleanalytics/src/utils/settings.ts +114 -0
  471. package/connectors/connect-googleanalytics/src/utils/storage.ts +198 -0
  472. package/connectors/connect-googleanalytics/tsconfig.json +16 -0
  473. package/connectors/connect-googlebigquery/.env.example +11 -0
  474. package/connectors/connect-googlebigquery/CLAUDE.md +272 -0
  475. package/connectors/connect-googlebigquery/README.md +39 -0
  476. package/connectors/connect-googlebigquery/package.json +49 -0
  477. package/connectors/connect-googlebigquery/src/api/client.ts +213 -0
  478. package/connectors/connect-googlebigquery/src/api/example.ts +48 -0
  479. package/connectors/connect-googlebigquery/src/api/index.ts +51 -0
  480. package/connectors/connect-googlebigquery/src/cli/index.ts +254 -0
  481. package/connectors/connect-googlebigquery/src/index.ts +103 -0
  482. package/connectors/connect-googlebigquery/src/types/index.ts +237 -0
  483. package/connectors/connect-googlebigquery/src/utils/auth.ts +274 -0
  484. package/connectors/connect-googlebigquery/src/utils/bulk.ts +212 -0
  485. package/connectors/connect-googlebigquery/src/utils/config.ts +326 -0
  486. package/connectors/connect-googlebigquery/src/utils/output.ts +175 -0
  487. package/connectors/connect-googlebigquery/src/utils/settings.ts +114 -0
  488. package/connectors/connect-googlebigquery/src/utils/storage.ts +198 -0
  489. package/connectors/connect-googlebigquery/tsconfig.json +16 -0
  490. package/connectors/connect-googlebooks/.env.example +11 -0
  491. package/connectors/connect-googlebooks/CLAUDE.md +272 -0
  492. package/connectors/connect-googlebooks/README.md +39 -0
  493. package/connectors/connect-googlebooks/package.json +49 -0
  494. package/connectors/connect-googlebooks/src/api/client.ts +213 -0
  495. package/connectors/connect-googlebooks/src/api/example.ts +48 -0
  496. package/connectors/connect-googlebooks/src/api/index.ts +51 -0
  497. package/connectors/connect-googlebooks/src/cli/index.ts +254 -0
  498. package/connectors/connect-googlebooks/src/index.ts +103 -0
  499. package/connectors/connect-googlebooks/src/types/index.ts +237 -0
  500. package/connectors/connect-googlebooks/src/utils/auth.ts +274 -0
  501. package/connectors/connect-googlebooks/src/utils/bulk.ts +212 -0
  502. package/connectors/connect-googlebooks/src/utils/config.ts +326 -0
  503. package/connectors/connect-googlebooks/src/utils/output.ts +175 -0
  504. package/connectors/connect-googlebooks/src/utils/settings.ts +114 -0
  505. package/connectors/connect-googlebooks/src/utils/storage.ts +198 -0
  506. package/connectors/connect-googlebooks/tsconfig.json +16 -0
  507. package/connectors/connect-googlebusinessprofile/.env.example +11 -0
  508. package/connectors/connect-googlebusinessprofile/CLAUDE.md +272 -0
  509. package/connectors/connect-googlebusinessprofile/README.md +39 -0
  510. package/connectors/connect-googlebusinessprofile/package.json +49 -0
  511. package/connectors/connect-googlebusinessprofile/src/api/client.ts +213 -0
  512. package/connectors/connect-googlebusinessprofile/src/api/example.ts +48 -0
  513. package/connectors/connect-googlebusinessprofile/src/api/index.ts +51 -0
  514. package/connectors/connect-googlebusinessprofile/src/cli/index.ts +254 -0
  515. package/connectors/connect-googlebusinessprofile/src/index.ts +103 -0
  516. package/connectors/connect-googlebusinessprofile/src/types/index.ts +237 -0
  517. package/connectors/connect-googlebusinessprofile/src/utils/auth.ts +274 -0
  518. package/connectors/connect-googlebusinessprofile/src/utils/bulk.ts +212 -0
  519. package/connectors/connect-googlebusinessprofile/src/utils/config.ts +326 -0
  520. package/connectors/connect-googlebusinessprofile/src/utils/output.ts +175 -0
  521. package/connectors/connect-googlebusinessprofile/src/utils/settings.ts +114 -0
  522. package/connectors/connect-googlebusinessprofile/src/utils/storage.ts +198 -0
  523. package/connectors/connect-googlebusinessprofile/tsconfig.json +16 -0
  524. package/connectors/connect-googlechat/.env.example +11 -0
  525. package/connectors/connect-googlechat/CLAUDE.md +272 -0
  526. package/connectors/connect-googlechat/README.md +194 -0
  527. package/connectors/connect-googlechat/package.json +53 -0
  528. package/connectors/connect-googlechat/scripts/release.ts +179 -0
  529. package/connectors/connect-googlechat/src/api/client.ts +213 -0
  530. package/connectors/connect-googlechat/src/api/example.ts +48 -0
  531. package/connectors/connect-googlechat/src/api/index.ts +51 -0
  532. package/connectors/connect-googlechat/src/cli/index.ts +254 -0
  533. package/connectors/connect-googlechat/src/index.ts +103 -0
  534. package/connectors/connect-googlechat/src/types/index.ts +237 -0
  535. package/connectors/connect-googlechat/src/utils/auth.ts +274 -0
  536. package/connectors/connect-googlechat/src/utils/bulk.ts +212 -0
  537. package/connectors/connect-googlechat/src/utils/config.ts +326 -0
  538. package/connectors/connect-googlechat/src/utils/output.ts +175 -0
  539. package/connectors/connect-googlechat/src/utils/settings.ts +114 -0
  540. package/connectors/connect-googlechat/src/utils/storage.ts +198 -0
  541. package/connectors/connect-googlechat/tsconfig.json +16 -0
  542. package/connectors/connect-googleforms/.env.example +11 -0
  543. package/connectors/connect-googleforms/CLAUDE.md +272 -0
  544. package/connectors/connect-googleforms/README.md +194 -0
  545. package/connectors/connect-googleforms/package.json +53 -0
  546. package/connectors/connect-googleforms/scripts/release.ts +179 -0
  547. package/connectors/connect-googleforms/src/api/client.ts +213 -0
  548. package/connectors/connect-googleforms/src/api/example.ts +48 -0
  549. package/connectors/connect-googleforms/src/api/index.ts +51 -0
  550. package/connectors/connect-googleforms/src/cli/index.ts +254 -0
  551. package/connectors/connect-googleforms/src/index.ts +103 -0
  552. package/connectors/connect-googleforms/src/types/index.ts +237 -0
  553. package/connectors/connect-googleforms/src/utils/auth.ts +274 -0
  554. package/connectors/connect-googleforms/src/utils/bulk.ts +212 -0
  555. package/connectors/connect-googleforms/src/utils/config.ts +326 -0
  556. package/connectors/connect-googleforms/src/utils/output.ts +175 -0
  557. package/connectors/connect-googleforms/src/utils/settings.ts +114 -0
  558. package/connectors/connect-googleforms/src/utils/storage.ts +198 -0
  559. package/connectors/connect-googleforms/tsconfig.json +16 -0
  560. package/connectors/connect-googleperspective/.env.example +11 -0
  561. package/connectors/connect-googleperspective/CLAUDE.md +272 -0
  562. package/connectors/connect-googleperspective/README.md +194 -0
  563. package/connectors/connect-googleperspective/package.json +54 -0
  564. package/connectors/connect-googleperspective/scripts/release.ts +179 -0
  565. package/connectors/connect-googleperspective/src/api/client.ts +213 -0
  566. package/connectors/connect-googleperspective/src/api/example.ts +48 -0
  567. package/connectors/connect-googleperspective/src/api/index.ts +51 -0
  568. package/connectors/connect-googleperspective/src/cli/index.ts +254 -0
  569. package/connectors/connect-googleperspective/src/index.ts +103 -0
  570. package/connectors/connect-googleperspective/src/types/index.ts +237 -0
  571. package/connectors/connect-googleperspective/src/utils/auth.ts +274 -0
  572. package/connectors/connect-googleperspective/src/utils/bulk.ts +212 -0
  573. package/connectors/connect-googleperspective/src/utils/config.ts +326 -0
  574. package/connectors/connect-googleperspective/src/utils/output.ts +175 -0
  575. package/connectors/connect-googleperspective/src/utils/settings.ts +114 -0
  576. package/connectors/connect-googleperspective/src/utils/storage.ts +198 -0
  577. package/connectors/connect-googleperspective/tsconfig.json +16 -0
  578. package/connectors/connect-googlephotos/.env.example +4 -0
  579. package/connectors/connect-googlephotos/CLAUDE.md +107 -0
  580. package/connectors/connect-googlephotos/README.md +194 -0
  581. package/connectors/connect-googlephotos/package.json +54 -0
  582. package/connectors/connect-googlephotos/scripts/publish.ts +74 -0
  583. package/connectors/connect-googlephotos/src/api/albums.ts +180 -0
  584. package/connectors/connect-googlephotos/src/api/client.ts +159 -0
  585. package/connectors/connect-googlephotos/src/api/index.ts +53 -0
  586. package/connectors/connect-googlephotos/src/api/media.ts +238 -0
  587. package/connectors/connect-googlephotos/src/api/upload.ts +204 -0
  588. package/connectors/connect-googlephotos/src/cli/index.ts +754 -0
  589. package/connectors/connect-googlephotos/src/index.ts +35 -0
  590. package/connectors/connect-googlephotos/src/types/index.ts +336 -0
  591. package/connectors/connect-googlephotos/src/utils/auth.ts +258 -0
  592. package/connectors/connect-googlephotos/src/utils/config.ts +419 -0
  593. package/connectors/connect-googlephotos/src/utils/output.ts +239 -0
  594. package/connectors/connect-googlephotos/tsconfig.json +15 -0
  595. package/dist/index.js +238 -0
  596. package/package.json +1 -1
@@ -0,0 +1,1259 @@
1
+ #!/usr/bin/env bun
2
+ import { program } from 'commander';
3
+ import chalk from 'chalk';
4
+ import { GoogleAds } from '../api';
5
+ import {
6
+ getCurrentProfile,
7
+ setCurrentProfile,
8
+ listProfiles,
9
+ createProfile,
10
+ deleteProfile,
11
+ profileExists,
12
+ setProfileOverride,
13
+ setCredentials,
14
+ setDeveloperToken,
15
+ getDeveloperToken,
16
+ getClientId,
17
+ getClientSecret,
18
+ isAuthenticated,
19
+ loadTokens,
20
+ saveTokens,
21
+ clearTokens,
22
+ getCustomerId,
23
+ setCustomerId,
24
+ getLoginCustomerId,
25
+ setLoginCustomerId,
26
+ getAccountName,
27
+ setAccountName,
28
+ getConfigDir,
29
+ } from '../utils/config';
30
+ import {
31
+ getAuthUrl,
32
+ startCallbackServer,
33
+ getValidAccessToken,
34
+ } from '../utils/auth';
35
+ import {
36
+ success,
37
+ error,
38
+ info,
39
+ print,
40
+ formatMicros,
41
+ formatNumber,
42
+ formatPercent,
43
+ formatCustomerId,
44
+ } from '../utils/output';
45
+ import type { KeywordMatchType, CampaignStatus, AdGroupStatus, AdStatus } from '../types';
46
+
47
+ // ============================================
48
+ // Helper Functions
49
+ // ============================================
50
+
51
+ async function getClient(customerId?: string): Promise<GoogleAds> {
52
+ const accessToken = await getValidAccessToken();
53
+ const developerToken = getDeveloperToken();
54
+ const resolvedCustomerId = customerId || getCustomerId();
55
+ const loginCustomerId = getLoginCustomerId();
56
+
57
+ if (!developerToken) {
58
+ throw new Error('Developer token not configured. Run "connect-googleads config set-developer-token <token>"');
59
+ }
60
+
61
+ return new GoogleAds({
62
+ accessToken,
63
+ developerToken,
64
+ customerId: resolvedCustomerId,
65
+ loginCustomerId,
66
+ });
67
+ }
68
+
69
+ function formatCampaignRow(row: any): void {
70
+ const campaign = row.campaign || {};
71
+ const metrics = row.metrics || {};
72
+
73
+ console.log(`
74
+ ${chalk.bold(campaign.name || 'Unknown')} (${campaign.id || 'N/A'})
75
+ Status: ${campaign.status || 'N/A'}
76
+ Channel: ${campaign.advertisingChannelType || 'N/A'}
77
+ Bidding: ${campaign.biddingStrategyType || 'N/A'}
78
+ Impressions: ${formatNumber(metrics.impressions)}
79
+ Clicks: ${formatNumber(metrics.clicks)}
80
+ Cost: ${formatMicros(metrics.costMicros)}
81
+ Conversions: ${metrics.conversions?.toFixed(2) || '0'}
82
+ CTR: ${formatPercent(metrics.ctr)}
83
+ Avg CPC: ${formatMicros(metrics.averageCpc ? metrics.averageCpc * 1000000 : 0)}
84
+ `);
85
+ }
86
+
87
+ function formatAdGroupRow(row: any): void {
88
+ const adGroup = row.adGroup || {};
89
+ const campaign = row.campaign || {};
90
+ const metrics = row.metrics || {};
91
+
92
+ console.log(`
93
+ ${chalk.bold(adGroup.name || 'Unknown')} (${adGroup.id || 'N/A'})
94
+ Campaign: ${campaign.name || 'N/A'}
95
+ Status: ${adGroup.status || 'N/A'}
96
+ Type: ${adGroup.type || 'N/A'}
97
+ CPC Bid: ${formatMicros(adGroup.cpcBidMicros)}
98
+ Impressions: ${formatNumber(metrics.impressions)}
99
+ Clicks: ${formatNumber(metrics.clicks)}
100
+ Cost: ${formatMicros(metrics.costMicros)}
101
+ `);
102
+ }
103
+
104
+ function formatKeywordRow(row: any): void {
105
+ const criterion = row.adGroupCriterion || {};
106
+ const keyword = criterion.keyword || {};
107
+ const adGroup = row.adGroup || {};
108
+ const metrics = row.metrics || {};
109
+
110
+ console.log(`
111
+ ${chalk.bold(keyword.text || 'Unknown')} [${keyword.matchType || 'N/A'}]
112
+ Ad Group: ${adGroup.name || 'N/A'} (${adGroup.id || 'N/A'})
113
+ Status: ${criterion.status || 'N/A'}
114
+ Quality Score: ${criterion.qualityInfo?.qualityScore || 'N/A'}
115
+ CPC Bid: ${formatMicros(criterion.cpcBidMicros)}
116
+ Impressions: ${formatNumber(metrics.impressions)}
117
+ Clicks: ${formatNumber(metrics.clicks)}
118
+ Cost: ${formatMicros(metrics.costMicros)}
119
+ CTR: ${formatPercent(metrics.ctr)}
120
+ `);
121
+ }
122
+
123
+ // ============================================
124
+ // CLI Setup
125
+ // ============================================
126
+
127
+ program
128
+ .name('connect-googleads')
129
+ .description('Google Ads API connector CLI')
130
+ .version('0.1.0')
131
+ .option('-p, --profile <profile>', 'Use specific profile')
132
+ .option('-c, --customer <customerId>', 'Use specific customer ID')
133
+ .option('--json', 'Output as JSON')
134
+ .hook('preAction', (thisCommand) => {
135
+ const opts = thisCommand.opts();
136
+ if (opts.profile) {
137
+ setProfileOverride(opts.profile);
138
+ }
139
+ });
140
+
141
+ // ============================================
142
+ // Auth Commands
143
+ // ============================================
144
+
145
+ const auth = program.command('auth').description('Authentication commands');
146
+
147
+ auth
148
+ .command('setup')
149
+ .description('Setup OAuth credentials')
150
+ .argument('<clientId>', 'OAuth2 Client ID')
151
+ .argument('<clientSecret>', 'OAuth2 Client Secret')
152
+ .action((clientId: string, clientSecret: string) => {
153
+ setCredentials(clientId, clientSecret);
154
+ success(`OAuth credentials saved for profile "${getCurrentProfile()}"`);
155
+ info('Now run: connect-googleads auth login');
156
+ });
157
+
158
+ auth
159
+ .command('login')
160
+ .description('Authenticate with Google Ads')
161
+ .action(async () => {
162
+ const clientId = getClientId();
163
+ const clientSecret = getClientSecret();
164
+
165
+ if (!clientId || !clientSecret) {
166
+ error('OAuth credentials not configured. Run "connect-googleads auth setup <clientId> <clientSecret>" first.');
167
+ process.exit(1);
168
+ }
169
+
170
+ info('Starting OAuth flow...');
171
+ const authUrl = getAuthUrl();
172
+
173
+ console.log('\nOpen this URL in your browser:\n');
174
+ console.log(chalk.cyan(authUrl));
175
+ console.log('\nWaiting for authentication...\n');
176
+
177
+ // Try to open browser automatically
178
+ try {
179
+ const open = await import('open');
180
+ await open.default(authUrl);
181
+ } catch {
182
+ // Manual open required
183
+ }
184
+
185
+ const result = await startCallbackServer();
186
+
187
+ if (result.success && result.tokens) {
188
+ saveTokens(result.tokens);
189
+ success('Authentication successful!');
190
+
191
+ // Try to get account info
192
+ try {
193
+ const client = await getClient();
194
+ const accessible = await client.listAccessibleCustomers();
195
+ if (accessible.resourceNames?.length > 0) {
196
+ const firstCustomer = accessible.resourceNames[0].split('/')[1];
197
+ info(`Found ${accessible.resourceNames.length} accessible customer(s)`);
198
+ info(`First customer ID: ${formatCustomerId(firstCustomer)}`);
199
+ info('Run: connect-googleads config set-customer <customerId> to set your customer ID');
200
+ }
201
+ } catch (err) {
202
+ info('Run: connect-googleads config set-customer <customerId> to set your customer ID');
203
+ }
204
+ } else {
205
+ error(`Authentication failed: ${result.error}`);
206
+ process.exit(1);
207
+ }
208
+ });
209
+
210
+ auth
211
+ .command('logout')
212
+ .description('Clear authentication tokens')
213
+ .action(() => {
214
+ clearTokens();
215
+ success(`Logged out from profile "${getCurrentProfile()}"`);
216
+ });
217
+
218
+ auth
219
+ .command('status')
220
+ .description('Check authentication status')
221
+ .action(() => {
222
+ const profile = getCurrentProfile();
223
+ const authenticated = isAuthenticated();
224
+ const tokens = loadTokens();
225
+ const customerId = getCustomerId();
226
+ const developerToken = getDeveloperToken();
227
+
228
+ console.log(`
229
+ Profile: ${chalk.bold(profile)}
230
+ Authenticated: ${authenticated ? chalk.green('Yes') : chalk.red('No')}
231
+ ${tokens ? `Token expires: ${new Date(tokens.expiresAt).toLocaleString()}` : ''}
232
+ Customer ID: ${customerId ? formatCustomerId(customerId) : chalk.yellow('Not set')}
233
+ Developer Token: ${developerToken ? chalk.green('Set') : chalk.red('Not set')}
234
+ `);
235
+ });
236
+
237
+ // ============================================
238
+ // Config Commands
239
+ // ============================================
240
+
241
+ const config = program.command('config').description('Configuration commands');
242
+
243
+ config
244
+ .command('set-customer')
245
+ .description('Set default customer ID')
246
+ .argument('<customerId>', 'Google Ads customer ID')
247
+ .action((customerId: string) => {
248
+ setCustomerId(customerId.replace(/-/g, ''));
249
+ success(`Customer ID set to ${formatCustomerId(customerId)}`);
250
+ });
251
+
252
+ config
253
+ .command('set-login-customer')
254
+ .description('Set login customer ID (for manager accounts)')
255
+ .argument('<customerId>', 'Login customer ID')
256
+ .action((customerId: string) => {
257
+ setLoginCustomerId(customerId.replace(/-/g, ''));
258
+ success(`Login customer ID set to ${formatCustomerId(customerId)}`);
259
+ });
260
+
261
+ config
262
+ .command('set-developer-token')
263
+ .description('Set developer token')
264
+ .argument('<token>', 'Google Ads API developer token')
265
+ .action((token: string) => {
266
+ setDeveloperToken(token);
267
+ success('Developer token saved');
268
+ });
269
+
270
+ config
271
+ .command('show')
272
+ .description('Show current configuration')
273
+ .action(() => {
274
+ console.log(`
275
+ Profile: ${chalk.bold(getCurrentProfile())}
276
+ Config Directory: ${getConfigDir()}
277
+ Customer ID: ${getCustomerId() ? formatCustomerId(getCustomerId()!) : chalk.yellow('Not set')}
278
+ Login Customer ID: ${getLoginCustomerId() ? formatCustomerId(getLoginCustomerId()!) : 'Not set'}
279
+ Developer Token: ${getDeveloperToken() ? chalk.green('Set') : chalk.red('Not set')}
280
+ Client ID: ${getClientId() ? chalk.green('Set') : chalk.red('Not set')}
281
+ Client Secret: ${getClientSecret() ? chalk.green('Set') : chalk.red('Not set')}
282
+ `);
283
+ });
284
+
285
+ // ============================================
286
+ // Profile Commands
287
+ // ============================================
288
+
289
+ const profile = program.command('profile').description('Profile management');
290
+
291
+ profile
292
+ .command('list')
293
+ .description('List all profiles')
294
+ .action(() => {
295
+ const profiles = listProfiles();
296
+ const current = getCurrentProfile();
297
+
298
+ if (profiles.length === 0) {
299
+ console.log('No profiles found');
300
+ return;
301
+ }
302
+
303
+ console.log('\nProfiles:');
304
+ for (const p of profiles) {
305
+ const marker = p === current ? chalk.green(' (active)') : '';
306
+ console.log(` ${p}${marker}`);
307
+ }
308
+ console.log('');
309
+ });
310
+
311
+ profile
312
+ .command('use')
313
+ .description('Switch to a profile')
314
+ .argument('<name>', 'Profile name')
315
+ .action((name: string) => {
316
+ if (!profileExists(name)) {
317
+ error(`Profile "${name}" does not exist`);
318
+ process.exit(1);
319
+ }
320
+ setCurrentProfile(name);
321
+ success(`Switched to profile "${name}"`);
322
+ });
323
+
324
+ profile
325
+ .command('create')
326
+ .description('Create a new profile')
327
+ .argument('<name>', 'Profile name')
328
+ .action((name: string) => {
329
+ if (profileExists(name)) {
330
+ error(`Profile "${name}" already exists`);
331
+ process.exit(1);
332
+ }
333
+ createProfile(name);
334
+ success(`Created profile "${name}"`);
335
+ info(`Run: connect-googleads profile use ${name}`);
336
+ });
337
+
338
+ profile
339
+ .command('delete')
340
+ .description('Delete a profile')
341
+ .argument('<name>', 'Profile name')
342
+ .action((name: string) => {
343
+ if (deleteProfile(name)) {
344
+ success(`Deleted profile "${name}"`);
345
+ } else {
346
+ error(`Could not delete profile "${name}"`);
347
+ }
348
+ });
349
+
350
+ // ============================================
351
+ // Account Commands
352
+ // ============================================
353
+
354
+ const account = program.command('account').description('Account commands');
355
+
356
+ account
357
+ .command('info')
358
+ .description('Get account information')
359
+ .action(async () => {
360
+ try {
361
+ const client = await getClient();
362
+ const response = await client.getCustomer();
363
+
364
+ if (program.opts().json) {
365
+ print(response, 'json');
366
+ return;
367
+ }
368
+
369
+ const customer = response.results?.[0]?.customer || {};
370
+ console.log(`
371
+ ${chalk.bold('Account Information')}
372
+ ID: ${formatCustomerId(customer.id)}
373
+ Name: ${customer.descriptiveName || 'N/A'}
374
+ Currency: ${customer.currencyCode || 'N/A'}
375
+ Time Zone: ${customer.timeZone || 'N/A'}
376
+ Manager: ${customer.manager ? 'Yes' : 'No'}
377
+ Test Account: ${customer.testAccount ? 'Yes' : 'No'}
378
+ `);
379
+ } catch (err: any) {
380
+ error(err.message);
381
+ process.exit(1);
382
+ }
383
+ });
384
+
385
+ account
386
+ .command('customers')
387
+ .description('List accessible customers')
388
+ .action(async () => {
389
+ try {
390
+ const client = await getClient();
391
+ const response = await client.listAccessibleCustomers();
392
+
393
+ if (program.opts().json) {
394
+ print(response, 'json');
395
+ return;
396
+ }
397
+
398
+ console.log('\nAccessible Customers:');
399
+ for (const resourceName of response.resourceNames || []) {
400
+ const id = resourceName.split('/')[1];
401
+ console.log(` ${formatCustomerId(id)}`);
402
+ }
403
+ console.log('');
404
+ } catch (err: any) {
405
+ error(err.message);
406
+ process.exit(1);
407
+ }
408
+ });
409
+
410
+ account
411
+ .command('clients')
412
+ .description('List client accounts (for manager accounts)')
413
+ .action(async () => {
414
+ try {
415
+ const client = await getClient();
416
+ const response = await client.getCustomerClients();
417
+
418
+ if (program.opts().json) {
419
+ print(response, 'json');
420
+ return;
421
+ }
422
+
423
+ console.log('\nClient Accounts:');
424
+ for (const row of response.results || []) {
425
+ const cc = row.customerClient || {};
426
+ console.log(` ${formatCustomerId(cc.id)} - ${cc.descriptiveName || 'N/A'}`);
427
+ }
428
+ console.log('');
429
+ } catch (err: any) {
430
+ error(err.message);
431
+ process.exit(1);
432
+ }
433
+ });
434
+
435
+ // ============================================
436
+ // Campaign Commands
437
+ // ============================================
438
+
439
+ const campaigns = program.command('campaigns').description('Campaign management');
440
+
441
+ campaigns
442
+ .command('list')
443
+ .description('List campaigns')
444
+ .option('-s, --status <status>', 'Filter by status (ENABLED, PAUSED, REMOVED)')
445
+ .option('-l, --limit <limit>', 'Limit results', parseInt)
446
+ .action(async (options) => {
447
+ try {
448
+ const client = await getClient(program.opts().customer);
449
+ const response = await client.campaigns.list({
450
+ status: options.status as CampaignStatus,
451
+ limit: options.limit,
452
+ });
453
+
454
+ if (program.opts().json) {
455
+ print(response, 'json');
456
+ return;
457
+ }
458
+
459
+ if (!response.results?.length) {
460
+ info('No campaigns found');
461
+ return;
462
+ }
463
+
464
+ console.log(`\nFound ${response.results.length} campaign(s):`);
465
+ for (const row of response.results) {
466
+ formatCampaignRow(row);
467
+ }
468
+ } catch (err: any) {
469
+ error(err.message);
470
+ process.exit(1);
471
+ }
472
+ });
473
+
474
+ campaigns
475
+ .command('get')
476
+ .description('Get campaign details')
477
+ .argument('<campaignId>', 'Campaign ID')
478
+ .action(async (campaignId: string) => {
479
+ try {
480
+ const client = await getClient(program.opts().customer);
481
+ const response = await client.campaigns.get(campaignId);
482
+
483
+ if (program.opts().json) {
484
+ print(response, 'json');
485
+ return;
486
+ }
487
+
488
+ if (response.results?.[0]) {
489
+ formatCampaignRow(response.results[0]);
490
+ }
491
+ } catch (err: any) {
492
+ error(err.message);
493
+ process.exit(1);
494
+ }
495
+ });
496
+
497
+ campaigns
498
+ .command('create')
499
+ .description('Create a new campaign')
500
+ .argument('<name>', 'Campaign name')
501
+ .argument('<budgetMicros>', 'Daily budget in micros')
502
+ .option('-t, --type <type>', 'Channel type (SEARCH, DISPLAY, etc.)', 'SEARCH')
503
+ .option('-s, --status <status>', 'Initial status', 'PAUSED')
504
+ .option('-b, --bidding <strategy>', 'Bidding strategy')
505
+ .action(async (name: string, budgetMicros: string, options) => {
506
+ try {
507
+ const client = await getClient(program.opts().customer);
508
+ const response = await client.campaigns.create(name, budgetMicros, options.type, {
509
+ status: options.status,
510
+ biddingStrategy: options.bidding,
511
+ });
512
+
513
+ if (program.opts().json) {
514
+ print(response, 'json');
515
+ return;
516
+ }
517
+
518
+ success(`Created campaign: ${response.results?.[0]?.resourceName}`);
519
+ } catch (err: any) {
520
+ error(err.message);
521
+ process.exit(1);
522
+ }
523
+ });
524
+
525
+ campaigns
526
+ .command('pause')
527
+ .description('Pause a campaign')
528
+ .argument('<campaignId>', 'Campaign ID')
529
+ .action(async (campaignId: string) => {
530
+ try {
531
+ const client = await getClient(program.opts().customer);
532
+ await client.campaigns.pause(campaignId);
533
+ success(`Paused campaign ${campaignId}`);
534
+ } catch (err: any) {
535
+ error(err.message);
536
+ process.exit(1);
537
+ }
538
+ });
539
+
540
+ campaigns
541
+ .command('enable')
542
+ .description('Enable a campaign')
543
+ .argument('<campaignId>', 'Campaign ID')
544
+ .action(async (campaignId: string) => {
545
+ try {
546
+ const client = await getClient(program.opts().customer);
547
+ await client.campaigns.enable(campaignId);
548
+ success(`Enabled campaign ${campaignId}`);
549
+ } catch (err: any) {
550
+ error(err.message);
551
+ process.exit(1);
552
+ }
553
+ });
554
+
555
+ campaigns
556
+ .command('remove')
557
+ .description('Remove a campaign')
558
+ .argument('<campaignId>', 'Campaign ID')
559
+ .action(async (campaignId: string) => {
560
+ try {
561
+ const client = await getClient(program.opts().customer);
562
+ await client.campaigns.remove(campaignId);
563
+ success(`Removed campaign ${campaignId}`);
564
+ } catch (err: any) {
565
+ error(err.message);
566
+ process.exit(1);
567
+ }
568
+ });
569
+
570
+ campaigns
571
+ .command('performance')
572
+ .description('Get campaign performance report')
573
+ .argument('<campaignId>', 'Campaign ID')
574
+ .argument('<startDate>', 'Start date (YYYY-MM-DD)')
575
+ .argument('<endDate>', 'End date (YYYY-MM-DD)')
576
+ .action(async (campaignId: string, startDate: string, endDate: string) => {
577
+ try {
578
+ const client = await getClient(program.opts().customer);
579
+ const response = await client.campaigns.getPerformance(campaignId, startDate, endDate);
580
+
581
+ if (program.opts().json) {
582
+ print(response, 'json');
583
+ return;
584
+ }
585
+
586
+ console.log(`\nPerformance for campaign ${campaignId}:`);
587
+ for (const row of response.results || []) {
588
+ const segments = row.segments || {};
589
+ const metrics = row.metrics || {};
590
+ console.log(` ${segments.date}: ${formatNumber(metrics.clicks)} clicks, ${formatMicros(metrics.costMicros)}, ${metrics.conversions?.toFixed(2) || 0} conv`);
591
+ }
592
+ } catch (err: any) {
593
+ error(err.message);
594
+ process.exit(1);
595
+ }
596
+ });
597
+
598
+ // ============================================
599
+ // Ad Group Commands
600
+ // ============================================
601
+
602
+ const adGroups = program.command('adgroups').description('Ad group management');
603
+
604
+ adGroups
605
+ .command('list')
606
+ .description('List ad groups')
607
+ .option('-c, --campaign <campaignId>', 'Filter by campaign')
608
+ .option('-s, --status <status>', 'Filter by status')
609
+ .option('-l, --limit <limit>', 'Limit results', parseInt)
610
+ .action(async (options) => {
611
+ try {
612
+ const client = await getClient(program.opts().customer);
613
+ const response = await client.adGroups.list({
614
+ campaignId: options.campaign,
615
+ status: options.status as AdGroupStatus,
616
+ limit: options.limit,
617
+ });
618
+
619
+ if (program.opts().json) {
620
+ print(response, 'json');
621
+ return;
622
+ }
623
+
624
+ if (!response.results?.length) {
625
+ info('No ad groups found');
626
+ return;
627
+ }
628
+
629
+ console.log(`\nFound ${response.results.length} ad group(s):`);
630
+ for (const row of response.results) {
631
+ formatAdGroupRow(row);
632
+ }
633
+ } catch (err: any) {
634
+ error(err.message);
635
+ process.exit(1);
636
+ }
637
+ });
638
+
639
+ adGroups
640
+ .command('get')
641
+ .description('Get ad group details')
642
+ .argument('<adGroupId>', 'Ad group ID')
643
+ .action(async (adGroupId: string) => {
644
+ try {
645
+ const client = await getClient(program.opts().customer);
646
+ const response = await client.adGroups.get(adGroupId);
647
+
648
+ if (program.opts().json) {
649
+ print(response, 'json');
650
+ return;
651
+ }
652
+
653
+ if (response.results?.[0]) {
654
+ formatAdGroupRow(response.results[0]);
655
+ }
656
+ } catch (err: any) {
657
+ error(err.message);
658
+ process.exit(1);
659
+ }
660
+ });
661
+
662
+ adGroups
663
+ .command('create')
664
+ .description('Create a new ad group')
665
+ .argument('<campaignId>', 'Campaign ID')
666
+ .argument('<name>', 'Ad group name')
667
+ .option('-s, --status <status>', 'Initial status', 'PAUSED')
668
+ .option('-t, --type <type>', 'Ad group type', 'SEARCH_STANDARD')
669
+ .option('-b, --bid <bidMicros>', 'CPC bid in micros')
670
+ .action(async (campaignId: string, name: string, options) => {
671
+ try {
672
+ const client = await getClient(program.opts().customer);
673
+ const response = await client.adGroups.create(campaignId, name, {
674
+ status: options.status,
675
+ type: options.type,
676
+ cpcBidMicros: options.bid,
677
+ });
678
+
679
+ if (program.opts().json) {
680
+ print(response, 'json');
681
+ return;
682
+ }
683
+
684
+ success(`Created ad group: ${response.results?.[0]?.resourceName}`);
685
+ } catch (err: any) {
686
+ error(err.message);
687
+ process.exit(1);
688
+ }
689
+ });
690
+
691
+ adGroups
692
+ .command('pause')
693
+ .description('Pause an ad group')
694
+ .argument('<adGroupId>', 'Ad group ID')
695
+ .action(async (adGroupId: string) => {
696
+ try {
697
+ const client = await getClient(program.opts().customer);
698
+ await client.adGroups.pause(adGroupId);
699
+ success(`Paused ad group ${adGroupId}`);
700
+ } catch (err: any) {
701
+ error(err.message);
702
+ process.exit(1);
703
+ }
704
+ });
705
+
706
+ adGroups
707
+ .command('enable')
708
+ .description('Enable an ad group')
709
+ .argument('<adGroupId>', 'Ad group ID')
710
+ .action(async (adGroupId: string) => {
711
+ try {
712
+ const client = await getClient(program.opts().customer);
713
+ await client.adGroups.enable(adGroupId);
714
+ success(`Enabled ad group ${adGroupId}`);
715
+ } catch (err: any) {
716
+ error(err.message);
717
+ process.exit(1);
718
+ }
719
+ });
720
+
721
+ adGroups
722
+ .command('set-bid')
723
+ .description('Set ad group bid')
724
+ .argument('<adGroupId>', 'Ad group ID')
725
+ .argument('<bidMicros>', 'CPC bid in micros')
726
+ .action(async (adGroupId: string, bidMicros: string) => {
727
+ try {
728
+ const client = await getClient(program.opts().customer);
729
+ await client.adGroups.setBid(adGroupId, bidMicros);
730
+ success(`Set bid for ad group ${adGroupId} to ${formatMicros(bidMicros)}`);
731
+ } catch (err: any) {
732
+ error(err.message);
733
+ process.exit(1);
734
+ }
735
+ });
736
+
737
+ // ============================================
738
+ // Ad Commands
739
+ // ============================================
740
+
741
+ const ads = program.command('ads').description('Ad management');
742
+
743
+ ads
744
+ .command('list')
745
+ .description('List ads')
746
+ .option('-g, --adgroup <adGroupId>', 'Filter by ad group')
747
+ .option('-c, --campaign <campaignId>', 'Filter by campaign')
748
+ .option('-s, --status <status>', 'Filter by status')
749
+ .option('-l, --limit <limit>', 'Limit results', parseInt)
750
+ .action(async (options) => {
751
+ try {
752
+ const client = await getClient(program.opts().customer);
753
+ const response = await client.ads.list({
754
+ adGroupId: options.adgroup,
755
+ campaignId: options.campaign,
756
+ status: options.status as AdStatus,
757
+ limit: options.limit,
758
+ });
759
+
760
+ if (program.opts().json) {
761
+ print(response, 'json');
762
+ return;
763
+ }
764
+
765
+ if (!response.results?.length) {
766
+ info('No ads found');
767
+ return;
768
+ }
769
+
770
+ console.log(`\nFound ${response.results.length} ad(s):`);
771
+ for (const row of response.results || []) {
772
+ const ad = row.adGroupAd?.ad || {};
773
+ const metrics = row.metrics || {};
774
+ console.log(`
775
+ ${chalk.bold(`Ad ${ad.id}`)} - ${row.adGroupAd?.status || 'N/A'}
776
+ Type: ${ad.type || 'N/A'}
777
+ Approval: ${row.adGroupAd?.policySummary?.approvalStatus || 'N/A'}
778
+ Impressions: ${formatNumber(metrics.impressions)}
779
+ Clicks: ${formatNumber(metrics.clicks)}
780
+ Cost: ${formatMicros(metrics.costMicros)}
781
+ `);
782
+ }
783
+ } catch (err: any) {
784
+ error(err.message);
785
+ process.exit(1);
786
+ }
787
+ });
788
+
789
+ ads
790
+ .command('create-rsa')
791
+ .description('Create a responsive search ad')
792
+ .argument('<adGroupId>', 'Ad group ID')
793
+ .requiredOption('-h, --headlines <headlines...>', 'Headlines (3-15)')
794
+ .requiredOption('-d, --descriptions <descriptions...>', 'Descriptions (2-4)')
795
+ .requiredOption('-u, --url <finalUrl>', 'Final URL')
796
+ .option('--path1 <path1>', 'Display URL path 1')
797
+ .option('--path2 <path2>', 'Display URL path 2')
798
+ .option('-s, --status <status>', 'Initial status', 'PAUSED')
799
+ .action(async (adGroupId: string, options) => {
800
+ try {
801
+ const client = await getClient(program.opts().customer);
802
+ const response = await client.ads.createResponsiveSearchAd(
803
+ adGroupId,
804
+ options.headlines,
805
+ options.descriptions,
806
+ [options.url],
807
+ {
808
+ path1: options.path1,
809
+ path2: options.path2,
810
+ status: options.status,
811
+ }
812
+ );
813
+
814
+ if (program.opts().json) {
815
+ print(response, 'json');
816
+ return;
817
+ }
818
+
819
+ success(`Created responsive search ad: ${response.results?.[0]?.resourceName}`);
820
+ } catch (err: any) {
821
+ error(err.message);
822
+ process.exit(1);
823
+ }
824
+ });
825
+
826
+ ads
827
+ .command('pause')
828
+ .description('Pause an ad')
829
+ .argument('<adGroupId>', 'Ad group ID')
830
+ .argument('<adId>', 'Ad ID')
831
+ .action(async (adGroupId: string, adId: string) => {
832
+ try {
833
+ const client = await getClient(program.opts().customer);
834
+ await client.ads.pause(adGroupId, adId);
835
+ success(`Paused ad ${adId}`);
836
+ } catch (err: any) {
837
+ error(err.message);
838
+ process.exit(1);
839
+ }
840
+ });
841
+
842
+ ads
843
+ .command('enable')
844
+ .description('Enable an ad')
845
+ .argument('<adGroupId>', 'Ad group ID')
846
+ .argument('<adId>', 'Ad ID')
847
+ .action(async (adGroupId: string, adId: string) => {
848
+ try {
849
+ const client = await getClient(program.opts().customer);
850
+ await client.ads.enable(adGroupId, adId);
851
+ success(`Enabled ad ${adId}`);
852
+ } catch (err: any) {
853
+ error(err.message);
854
+ process.exit(1);
855
+ }
856
+ });
857
+
858
+ ads
859
+ .command('remove')
860
+ .description('Remove an ad')
861
+ .argument('<adGroupId>', 'Ad group ID')
862
+ .argument('<adId>', 'Ad ID')
863
+ .action(async (adGroupId: string, adId: string) => {
864
+ try {
865
+ const client = await getClient(program.opts().customer);
866
+ await client.ads.remove(adGroupId, adId);
867
+ success(`Removed ad ${adId}`);
868
+ } catch (err: any) {
869
+ error(err.message);
870
+ process.exit(1);
871
+ }
872
+ });
873
+
874
+ // ============================================
875
+ // Keyword Commands
876
+ // ============================================
877
+
878
+ const keywords = program.command('keywords').description('Keyword management');
879
+
880
+ keywords
881
+ .command('list')
882
+ .description('List keywords')
883
+ .option('-g, --adgroup <adGroupId>', 'Filter by ad group')
884
+ .option('-c, --campaign <campaignId>', 'Filter by campaign')
885
+ .option('-s, --status <status>', 'Filter by status')
886
+ .option('-l, --limit <limit>', 'Limit results', parseInt)
887
+ .action(async (options) => {
888
+ try {
889
+ const client = await getClient(program.opts().customer);
890
+ const response = await client.keywords.list({
891
+ adGroupId: options.adgroup,
892
+ campaignId: options.campaign,
893
+ status: options.status,
894
+ limit: options.limit,
895
+ });
896
+
897
+ if (program.opts().json) {
898
+ print(response, 'json');
899
+ return;
900
+ }
901
+
902
+ if (!response.results?.length) {
903
+ info('No keywords found');
904
+ return;
905
+ }
906
+
907
+ console.log(`\nFound ${response.results.length} keyword(s):`);
908
+ for (const row of response.results) {
909
+ formatKeywordRow(row);
910
+ }
911
+ } catch (err: any) {
912
+ error(err.message);
913
+ process.exit(1);
914
+ }
915
+ });
916
+
917
+ keywords
918
+ .command('add')
919
+ .description('Add a keyword')
920
+ .argument('<adGroupId>', 'Ad group ID')
921
+ .argument('<keyword>', 'Keyword text')
922
+ .option('-m, --match <type>', 'Match type (EXACT, PHRASE, BROAD)', 'BROAD')
923
+ .option('-b, --bid <bidMicros>', 'CPC bid in micros')
924
+ .option('-s, --status <status>', 'Initial status', 'ENABLED')
925
+ .action(async (adGroupId: string, keyword: string, options) => {
926
+ try {
927
+ const client = await getClient(program.opts().customer);
928
+ const response = await client.keywords.addKeyword(
929
+ adGroupId,
930
+ keyword,
931
+ options.match as KeywordMatchType,
932
+ {
933
+ cpcBidMicros: options.bid,
934
+ status: options.status,
935
+ }
936
+ );
937
+
938
+ if (program.opts().json) {
939
+ print(response, 'json');
940
+ return;
941
+ }
942
+
943
+ success(`Added keyword: ${response.results?.[0]?.resourceName}`);
944
+ } catch (err: any) {
945
+ error(err.message);
946
+ process.exit(1);
947
+ }
948
+ });
949
+
950
+ keywords
951
+ .command('add-negative')
952
+ .description('Add negative keywords')
953
+ .argument('<adGroupId>', 'Ad group ID')
954
+ .argument('<keywords...>', 'Keywords to add as negatives')
955
+ .option('-m, --match <type>', 'Match type (EXACT, PHRASE, BROAD)', 'PHRASE')
956
+ .action(async (adGroupId: string, keywordList: string[], options) => {
957
+ try {
958
+ const client = await getClient(program.opts().customer);
959
+ const keywords = keywordList.map(text => ({
960
+ text,
961
+ matchType: options.match as KeywordMatchType,
962
+ }));
963
+
964
+ const response = await client.keywords.addNegative(adGroupId, keywords);
965
+
966
+ if (program.opts().json) {
967
+ print(response, 'json');
968
+ return;
969
+ }
970
+
971
+ success(`Added ${keywordList.length} negative keyword(s)`);
972
+ } catch (err: any) {
973
+ error(err.message);
974
+ process.exit(1);
975
+ }
976
+ });
977
+
978
+ keywords
979
+ .command('pause')
980
+ .description('Pause a keyword')
981
+ .argument('<adGroupId>', 'Ad group ID')
982
+ .argument('<criterionId>', 'Criterion ID')
983
+ .action(async (adGroupId: string, criterionId: string) => {
984
+ try {
985
+ const client = await getClient(program.opts().customer);
986
+ await client.keywords.pause(adGroupId, criterionId);
987
+ success(`Paused keyword ${criterionId}`);
988
+ } catch (err: any) {
989
+ error(err.message);
990
+ process.exit(1);
991
+ }
992
+ });
993
+
994
+ keywords
995
+ .command('enable')
996
+ .description('Enable a keyword')
997
+ .argument('<adGroupId>', 'Ad group ID')
998
+ .argument('<criterionId>', 'Criterion ID')
999
+ .action(async (adGroupId: string, criterionId: string) => {
1000
+ try {
1001
+ const client = await getClient(program.opts().customer);
1002
+ await client.keywords.enable(adGroupId, criterionId);
1003
+ success(`Enabled keyword ${criterionId}`);
1004
+ } catch (err: any) {
1005
+ error(err.message);
1006
+ process.exit(1);
1007
+ }
1008
+ });
1009
+
1010
+ keywords
1011
+ .command('remove')
1012
+ .description('Remove a keyword')
1013
+ .argument('<adGroupId>', 'Ad group ID')
1014
+ .argument('<criterionId>', 'Criterion ID')
1015
+ .action(async (adGroupId: string, criterionId: string) => {
1016
+ try {
1017
+ const client = await getClient(program.opts().customer);
1018
+ await client.keywords.remove(adGroupId, criterionId);
1019
+ success(`Removed keyword ${criterionId}`);
1020
+ } catch (err: any) {
1021
+ error(err.message);
1022
+ process.exit(1);
1023
+ }
1024
+ });
1025
+
1026
+ keywords
1027
+ .command('search-terms')
1028
+ .description('Get search terms report')
1029
+ .option('-c, --campaign <campaignId>', 'Filter by campaign')
1030
+ .option('-g, --adgroup <adGroupId>', 'Filter by ad group')
1031
+ .option('--start <date>', 'Start date (YYYY-MM-DD)')
1032
+ .option('--end <date>', 'End date (YYYY-MM-DD)')
1033
+ .option('-l, --limit <limit>', 'Limit results', parseInt)
1034
+ .action(async (options) => {
1035
+ try {
1036
+ const client = await getClient(program.opts().customer);
1037
+ const response = await client.keywords.getSearchTerms({
1038
+ campaignId: options.campaign,
1039
+ adGroupId: options.adgroup,
1040
+ startDate: options.start,
1041
+ endDate: options.end,
1042
+ limit: options.limit,
1043
+ });
1044
+
1045
+ if (program.opts().json) {
1046
+ print(response, 'json');
1047
+ return;
1048
+ }
1049
+
1050
+ console.log('\nSearch Terms:');
1051
+ for (const row of response.results || []) {
1052
+ const stv = row.searchTermView || {};
1053
+ const metrics = row.metrics || {};
1054
+ console.log(` "${stv.searchTerm}" - ${formatNumber(metrics.clicks)} clicks, ${formatMicros(metrics.costMicros)}`);
1055
+ }
1056
+ } catch (err: any) {
1057
+ error(err.message);
1058
+ process.exit(1);
1059
+ }
1060
+ });
1061
+
1062
+ // ============================================
1063
+ // Report Commands
1064
+ // ============================================
1065
+
1066
+ const reports = program.command('reports').description('Reporting commands');
1067
+
1068
+ reports
1069
+ .command('query')
1070
+ .description('Execute a custom GAQL query')
1071
+ .argument('<gaql>', 'GAQL query string')
1072
+ .action(async (gaql: string) => {
1073
+ try {
1074
+ const client = await getClient(program.opts().customer);
1075
+ const response = await client.reports.query(gaql);
1076
+ print(response, program.opts().json ? 'json' : 'pretty');
1077
+ } catch (err: any) {
1078
+ error(err.message);
1079
+ process.exit(1);
1080
+ }
1081
+ });
1082
+
1083
+ reports
1084
+ .command('account')
1085
+ .description('Account performance report')
1086
+ .argument('<startDate>', 'Start date (YYYY-MM-DD)')
1087
+ .argument('<endDate>', 'End date (YYYY-MM-DD)')
1088
+ .action(async (startDate: string, endDate: string) => {
1089
+ try {
1090
+ const client = await getClient(program.opts().customer);
1091
+ const response = await client.reports.accountPerformance(startDate, endDate);
1092
+
1093
+ if (program.opts().json) {
1094
+ print(response, 'json');
1095
+ return;
1096
+ }
1097
+
1098
+ console.log('\nAccount Performance:');
1099
+ for (const row of response.results || []) {
1100
+ const segments = row.segments || {};
1101
+ const metrics = row.metrics || {};
1102
+ console.log(` ${segments.date}: ${formatNumber(metrics.impressions)} imp, ${formatNumber(metrics.clicks)} clicks, ${formatMicros(metrics.costMicros)}, ${metrics.conversions?.toFixed(2) || 0} conv`);
1103
+ }
1104
+ } catch (err: any) {
1105
+ error(err.message);
1106
+ process.exit(1);
1107
+ }
1108
+ });
1109
+
1110
+ reports
1111
+ .command('campaign')
1112
+ .description('Campaign performance report')
1113
+ .argument('<startDate>', 'Start date (YYYY-MM-DD)')
1114
+ .argument('<endDate>', 'End date (YYYY-MM-DD)')
1115
+ .option('-c, --campaign <campaignId>', 'Filter by campaign')
1116
+ .action(async (startDate: string, endDate: string, options) => {
1117
+ try {
1118
+ const client = await getClient(program.opts().customer);
1119
+ const response = await client.reports.campaignPerformance(startDate, endDate, {
1120
+ campaignId: options.campaign,
1121
+ });
1122
+
1123
+ if (program.opts().json) {
1124
+ print(response, 'json');
1125
+ return;
1126
+ }
1127
+
1128
+ console.log('\nCampaign Performance:');
1129
+ for (const row of response.results || []) {
1130
+ const campaign = row.campaign || {};
1131
+ const segments = row.segments || {};
1132
+ const metrics = row.metrics || {};
1133
+ console.log(` ${segments.date} | ${campaign.name}: ${formatNumber(metrics.clicks)} clicks, ${formatMicros(metrics.costMicros)}`);
1134
+ }
1135
+ } catch (err: any) {
1136
+ error(err.message);
1137
+ process.exit(1);
1138
+ }
1139
+ });
1140
+
1141
+ reports
1142
+ .command('keyword')
1143
+ .description('Keyword performance report')
1144
+ .argument('<startDate>', 'Start date (YYYY-MM-DD)')
1145
+ .argument('<endDate>', 'End date (YYYY-MM-DD)')
1146
+ .option('-c, --campaign <campaignId>', 'Filter by campaign')
1147
+ .option('-g, --adgroup <adGroupId>', 'Filter by ad group')
1148
+ .option('-l, --limit <limit>', 'Limit results', parseInt)
1149
+ .action(async (startDate: string, endDate: string, options) => {
1150
+ try {
1151
+ const client = await getClient(program.opts().customer);
1152
+ const response = await client.reports.keywordPerformance(startDate, endDate, {
1153
+ campaignId: options.campaign,
1154
+ adGroupId: options.adgroup,
1155
+ limit: options.limit,
1156
+ });
1157
+
1158
+ if (program.opts().json) {
1159
+ print(response, 'json');
1160
+ return;
1161
+ }
1162
+
1163
+ print(response.results, 'pretty');
1164
+ } catch (err: any) {
1165
+ error(err.message);
1166
+ process.exit(1);
1167
+ }
1168
+ });
1169
+
1170
+ reports
1171
+ .command('device')
1172
+ .description('Device performance report')
1173
+ .argument('<startDate>', 'Start date (YYYY-MM-DD)')
1174
+ .argument('<endDate>', 'End date (YYYY-MM-DD)')
1175
+ .option('-c, --campaign <campaignId>', 'Filter by campaign')
1176
+ .action(async (startDate: string, endDate: string, options) => {
1177
+ try {
1178
+ const client = await getClient(program.opts().customer);
1179
+ const response = await client.reports.devicePerformance(startDate, endDate, {
1180
+ campaignId: options.campaign,
1181
+ });
1182
+
1183
+ if (program.opts().json) {
1184
+ print(response, 'json');
1185
+ return;
1186
+ }
1187
+
1188
+ console.log('\nDevice Performance:');
1189
+ for (const row of response.results || []) {
1190
+ const segments = row.segments || {};
1191
+ const metrics = row.metrics || {};
1192
+ console.log(` ${segments.device}: ${formatNumber(metrics.clicks)} clicks, ${formatMicros(metrics.costMicros)}, ${formatPercent(metrics.ctr)} CTR`);
1193
+ }
1194
+ } catch (err: any) {
1195
+ error(err.message);
1196
+ process.exit(1);
1197
+ }
1198
+ });
1199
+
1200
+ reports
1201
+ .command('geographic')
1202
+ .description('Geographic performance report')
1203
+ .argument('<startDate>', 'Start date (YYYY-MM-DD)')
1204
+ .argument('<endDate>', 'End date (YYYY-MM-DD)')
1205
+ .option('-c, --campaign <campaignId>', 'Filter by campaign')
1206
+ .action(async (startDate: string, endDate: string, options) => {
1207
+ try {
1208
+ const client = await getClient(program.opts().customer);
1209
+ const response = await client.reports.geographicPerformance(startDate, endDate, {
1210
+ campaignId: options.campaign,
1211
+ });
1212
+
1213
+ if (program.opts().json) {
1214
+ print(response, 'json');
1215
+ return;
1216
+ }
1217
+
1218
+ print(response.results, 'pretty');
1219
+ } catch (err: any) {
1220
+ error(err.message);
1221
+ process.exit(1);
1222
+ }
1223
+ });
1224
+
1225
+ reports
1226
+ .command('conversions')
1227
+ .description('Conversion tracking report')
1228
+ .argument('<startDate>', 'Start date (YYYY-MM-DD)')
1229
+ .argument('<endDate>', 'End date (YYYY-MM-DD)')
1230
+ .option('-c, --campaign <campaignId>', 'Filter by campaign')
1231
+ .action(async (startDate: string, endDate: string, options) => {
1232
+ try {
1233
+ const client = await getClient(program.opts().customer);
1234
+ const response = await client.reports.conversionReport(startDate, endDate, {
1235
+ campaignId: options.campaign,
1236
+ });
1237
+
1238
+ if (program.opts().json) {
1239
+ print(response, 'json');
1240
+ return;
1241
+ }
1242
+
1243
+ console.log('\nConversion Report:');
1244
+ for (const row of response.results || []) {
1245
+ const segments = row.segments || {};
1246
+ const metrics = row.metrics || {};
1247
+ console.log(` ${segments.conversionActionName}: ${metrics.conversions?.toFixed(2) || 0} conv, ${formatMicros(metrics.conversionsValue ? metrics.conversionsValue * 1000000 : 0)} value`);
1248
+ }
1249
+ } catch (err: any) {
1250
+ error(err.message);
1251
+ process.exit(1);
1252
+ }
1253
+ });
1254
+
1255
+ // ============================================
1256
+ // Parse and Execute
1257
+ // ============================================
1258
+
1259
+ program.parse();