@mcp-z/mcp-sheets 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 (363) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +181 -0
  3. package/bin/server.js +5 -0
  4. package/dist/cjs/constants.d.cts +7 -0
  5. package/dist/cjs/constants.d.ts +7 -0
  6. package/dist/cjs/constants.js +18 -0
  7. package/dist/cjs/constants.js.map +1 -0
  8. package/dist/cjs/index.d.cts +8 -0
  9. package/dist/cjs/index.d.ts +8 -0
  10. package/dist/cjs/index.js +314 -0
  11. package/dist/cjs/index.js.map +1 -0
  12. package/dist/cjs/lib/create-store.d.cts +2 -0
  13. package/dist/cjs/lib/create-store.d.ts +2 -0
  14. package/dist/cjs/lib/create-store.js +166 -0
  15. package/dist/cjs/lib/create-store.js.map +1 -0
  16. package/dist/cjs/mcp/index.d.cts +3 -0
  17. package/dist/cjs/mcp/index.d.ts +3 -0
  18. package/dist/cjs/mcp/index.js +66 -0
  19. package/dist/cjs/mcp/index.js.map +1 -0
  20. package/dist/cjs/mcp/prompts/a1-notation.d.cts +19 -0
  21. package/dist/cjs/mcp/prompts/a1-notation.d.ts +19 -0
  22. package/dist/cjs/mcp/prompts/a1-notation.js +169 -0
  23. package/dist/cjs/mcp/prompts/a1-notation.js.map +1 -0
  24. package/dist/cjs/mcp/prompts/index.d.cts +1 -0
  25. package/dist/cjs/mcp/prompts/index.d.ts +1 -0
  26. package/dist/cjs/mcp/prompts/index.js +17 -0
  27. package/dist/cjs/mcp/prompts/index.js.map +1 -0
  28. package/dist/cjs/mcp/resources/index.d.cts +1 -0
  29. package/dist/cjs/mcp/resources/index.d.ts +1 -0
  30. package/dist/cjs/mcp/resources/index.js +17 -0
  31. package/dist/cjs/mcp/resources/index.js.map +1 -0
  32. package/dist/cjs/mcp/resources/spreadsheet.d.cts +2 -0
  33. package/dist/cjs/mcp/resources/spreadsheet.d.ts +2 -0
  34. package/dist/cjs/mcp/resources/spreadsheet.js +258 -0
  35. package/dist/cjs/mcp/resources/spreadsheet.js.map +1 -0
  36. package/dist/cjs/mcp/tools/cells-format.d.cts +144 -0
  37. package/dist/cjs/mcp/tools/cells-format.d.ts +144 -0
  38. package/dist/cjs/mcp/tools/cells-format.js +484 -0
  39. package/dist/cjs/mcp/tools/cells-format.js.map +1 -0
  40. package/dist/cjs/mcp/tools/chart-create.d.cts +94 -0
  41. package/dist/cjs/mcp/tools/chart-create.d.ts +94 -0
  42. package/dist/cjs/mcp/tools/chart-create.js +575 -0
  43. package/dist/cjs/mcp/tools/chart-create.js.map +1 -0
  44. package/dist/cjs/mcp/tools/columns-get.d.cts +55 -0
  45. package/dist/cjs/mcp/tools/columns-get.d.ts +55 -0
  46. package/dist/cjs/mcp/tools/columns-get.js +289 -0
  47. package/dist/cjs/mcp/tools/columns-get.js.map +1 -0
  48. package/dist/cjs/mcp/tools/columns-update.d.cts +86 -0
  49. package/dist/cjs/mcp/tools/columns-update.d.ts +86 -0
  50. package/dist/cjs/mcp/tools/columns-update.js +482 -0
  51. package/dist/cjs/mcp/tools/columns-update.js.map +1 -0
  52. package/dist/cjs/mcp/tools/csv-get-columns.d.cts +43 -0
  53. package/dist/cjs/mcp/tools/csv-get-columns.d.ts +43 -0
  54. package/dist/cjs/mcp/tools/csv-get-columns.js +386 -0
  55. package/dist/cjs/mcp/tools/csv-get-columns.js.map +1 -0
  56. package/dist/cjs/mcp/tools/dimensions-batch-update.d.cts +118 -0
  57. package/dist/cjs/mcp/tools/dimensions-batch-update.d.ts +118 -0
  58. package/dist/cjs/mcp/tools/dimensions-batch-update.js +504 -0
  59. package/dist/cjs/mcp/tools/dimensions-batch-update.js.map +1 -0
  60. package/dist/cjs/mcp/tools/dimensions-move.d.cts +86 -0
  61. package/dist/cjs/mcp/tools/dimensions-move.d.ts +86 -0
  62. package/dist/cjs/mcp/tools/dimensions-move.js +359 -0
  63. package/dist/cjs/mcp/tools/dimensions-move.js.map +1 -0
  64. package/dist/cjs/mcp/tools/index.d.cts +26 -0
  65. package/dist/cjs/mcp/tools/index.d.ts +26 -0
  66. package/dist/cjs/mcp/tools/index.js +122 -0
  67. package/dist/cjs/mcp/tools/index.js.map +1 -0
  68. package/dist/cjs/mcp/tools/lib/dimension-operations.d.cts +48 -0
  69. package/dist/cjs/mcp/tools/lib/dimension-operations.d.ts +48 -0
  70. package/dist/cjs/mcp/tools/lib/dimension-operations.js +177 -0
  71. package/dist/cjs/mcp/tools/lib/dimension-operations.js.map +1 -0
  72. package/dist/cjs/mcp/tools/rows-append.d.cts +58 -0
  73. package/dist/cjs/mcp/tools/rows-append.d.ts +58 -0
  74. package/dist/cjs/mcp/tools/rows-append.js +335 -0
  75. package/dist/cjs/mcp/tools/rows-append.js.map +1 -0
  76. package/dist/cjs/mcp/tools/rows-csv-append.d.cts +67 -0
  77. package/dist/cjs/mcp/tools/rows-csv-append.d.ts +67 -0
  78. package/dist/cjs/mcp/tools/rows-csv-append.js +859 -0
  79. package/dist/cjs/mcp/tools/rows-csv-append.js.map +1 -0
  80. package/dist/cjs/mcp/tools/rows-get.d.cts +56 -0
  81. package/dist/cjs/mcp/tools/rows-get.d.ts +56 -0
  82. package/dist/cjs/mcp/tools/rows-get.js +292 -0
  83. package/dist/cjs/mcp/tools/rows-get.js.map +1 -0
  84. package/dist/cjs/mcp/tools/sheet-copy-to.d.cts +68 -0
  85. package/dist/cjs/mcp/tools/sheet-copy-to.d.ts +68 -0
  86. package/dist/cjs/mcp/tools/sheet-copy-to.js +341 -0
  87. package/dist/cjs/mcp/tools/sheet-copy-to.js.map +1 -0
  88. package/dist/cjs/mcp/tools/sheet-copy.d.cts +80 -0
  89. package/dist/cjs/mcp/tools/sheet-copy.d.ts +80 -0
  90. package/dist/cjs/mcp/tools/sheet-copy.js +394 -0
  91. package/dist/cjs/mcp/tools/sheet-copy.js.map +1 -0
  92. package/dist/cjs/mcp/tools/sheet-create.d.cts +56 -0
  93. package/dist/cjs/mcp/tools/sheet-create.d.ts +56 -0
  94. package/dist/cjs/mcp/tools/sheet-create.js +283 -0
  95. package/dist/cjs/mcp/tools/sheet-create.js.map +1 -0
  96. package/dist/cjs/mcp/tools/sheet-delete.d.cts +62 -0
  97. package/dist/cjs/mcp/tools/sheet-delete.d.ts +62 -0
  98. package/dist/cjs/mcp/tools/sheet-delete.js +341 -0
  99. package/dist/cjs/mcp/tools/sheet-delete.js.map +1 -0
  100. package/dist/cjs/mcp/tools/sheet-find.d.cts +48 -0
  101. package/dist/cjs/mcp/tools/sheet-find.d.ts +48 -0
  102. package/dist/cjs/mcp/tools/sheet-find.js +261 -0
  103. package/dist/cjs/mcp/tools/sheet-find.js.map +1 -0
  104. package/dist/cjs/mcp/tools/sheet-rename.d.cts +60 -0
  105. package/dist/cjs/mcp/tools/sheet-rename.d.ts +60 -0
  106. package/dist/cjs/mcp/tools/sheet-rename.js +305 -0
  107. package/dist/cjs/mcp/tools/sheet-rename.js.map +1 -0
  108. package/dist/cjs/mcp/tools/spreadsheet-copy.d.cts +58 -0
  109. package/dist/cjs/mcp/tools/spreadsheet-copy.d.ts +58 -0
  110. package/dist/cjs/mcp/tools/spreadsheet-copy.js +319 -0
  111. package/dist/cjs/mcp/tools/spreadsheet-copy.js.map +1 -0
  112. package/dist/cjs/mcp/tools/spreadsheet-create.d.cts +52 -0
  113. package/dist/cjs/mcp/tools/spreadsheet-create.d.ts +52 -0
  114. package/dist/cjs/mcp/tools/spreadsheet-create.js +270 -0
  115. package/dist/cjs/mcp/tools/spreadsheet-create.js.map +1 -0
  116. package/dist/cjs/mcp/tools/spreadsheet-find.d.cts +58 -0
  117. package/dist/cjs/mcp/tools/spreadsheet-find.d.ts +58 -0
  118. package/dist/cjs/mcp/tools/spreadsheet-find.js +334 -0
  119. package/dist/cjs/mcp/tools/spreadsheet-find.js.map +1 -0
  120. package/dist/cjs/mcp/tools/spreadsheet-rename.d.cts +56 -0
  121. package/dist/cjs/mcp/tools/spreadsheet-rename.d.ts +56 -0
  122. package/dist/cjs/mcp/tools/spreadsheet-rename.js +289 -0
  123. package/dist/cjs/mcp/tools/spreadsheet-rename.js.map +1 -0
  124. package/dist/cjs/mcp/tools/validation-set.d.cts +144 -0
  125. package/dist/cjs/mcp/tools/validation-set.d.ts +144 -0
  126. package/dist/cjs/mcp/tools/validation-set.js +564 -0
  127. package/dist/cjs/mcp/tools/validation-set.js.map +1 -0
  128. package/dist/cjs/mcp/tools/values-batch-update.d.cts +102 -0
  129. package/dist/cjs/mcp/tools/values-batch-update.d.ts +102 -0
  130. package/dist/cjs/mcp/tools/values-batch-update.js +409 -0
  131. package/dist/cjs/mcp/tools/values-batch-update.js.map +1 -0
  132. package/dist/cjs/mcp/tools/values-clear.d.cts +56 -0
  133. package/dist/cjs/mcp/tools/values-clear.d.ts +56 -0
  134. package/dist/cjs/mcp/tools/values-clear.js +308 -0
  135. package/dist/cjs/mcp/tools/values-clear.js.map +1 -0
  136. package/dist/cjs/mcp/tools/values-csv-update.d.cts +75 -0
  137. package/dist/cjs/mcp/tools/values-csv-update.d.ts +75 -0
  138. package/dist/cjs/mcp/tools/values-csv-update.js +500 -0
  139. package/dist/cjs/mcp/tools/values-csv-update.js.map +1 -0
  140. package/dist/cjs/mcp/tools/values-replace.d.cts +68 -0
  141. package/dist/cjs/mcp/tools/values-replace.d.ts +68 -0
  142. package/dist/cjs/mcp/tools/values-replace.js +378 -0
  143. package/dist/cjs/mcp/tools/values-replace.js.map +1 -0
  144. package/dist/cjs/mcp/tools/values-search.d.cts +74 -0
  145. package/dist/cjs/mcp/tools/values-search.d.ts +74 -0
  146. package/dist/cjs/mcp/tools/values-search.js +470 -0
  147. package/dist/cjs/mcp/tools/values-search.js.map +1 -0
  148. package/dist/cjs/package.json +1 -0
  149. package/dist/cjs/schemas/index.d.cts +14 -0
  150. package/dist/cjs/schemas/index.d.ts +14 -0
  151. package/dist/cjs/schemas/index.js +64 -0
  152. package/dist/cjs/schemas/index.js.map +1 -0
  153. package/dist/cjs/setup/config.d.cts +44 -0
  154. package/dist/cjs/setup/config.d.ts +44 -0
  155. package/dist/cjs/setup/config.js +201 -0
  156. package/dist/cjs/setup/config.js.map +1 -0
  157. package/dist/cjs/setup/http.d.cts +8 -0
  158. package/dist/cjs/setup/http.d.ts +8 -0
  159. package/dist/cjs/setup/http.js +260 -0
  160. package/dist/cjs/setup/http.js.map +1 -0
  161. package/dist/cjs/setup/index.d.cts +5 -0
  162. package/dist/cjs/setup/index.d.ts +5 -0
  163. package/dist/cjs/setup/index.js +46 -0
  164. package/dist/cjs/setup/index.js.map +1 -0
  165. package/dist/cjs/setup/oauth-google.d.cts +54 -0
  166. package/dist/cjs/setup/oauth-google.d.ts +54 -0
  167. package/dist/cjs/setup/oauth-google.js +332 -0
  168. package/dist/cjs/setup/oauth-google.js.map +1 -0
  169. package/dist/cjs/setup/runtime.d.cts +10 -0
  170. package/dist/cjs/setup/runtime.d.ts +10 -0
  171. package/dist/cjs/setup/runtime.js +353 -0
  172. package/dist/cjs/setup/runtime.js.map +1 -0
  173. package/dist/cjs/setup/stdio.d.cts +7 -0
  174. package/dist/cjs/setup/stdio.d.ts +7 -0
  175. package/dist/cjs/setup/stdio.js +239 -0
  176. package/dist/cjs/setup/stdio.js.map +1 -0
  177. package/dist/cjs/spreadsheet/column-utilities.d.cts +1 -0
  178. package/dist/cjs/spreadsheet/column-utilities.d.ts +1 -0
  179. package/dist/cjs/spreadsheet/column-utilities.js +21 -0
  180. package/dist/cjs/spreadsheet/column-utilities.js.map +1 -0
  181. package/dist/cjs/spreadsheet/csv-streaming.d.cts +19 -0
  182. package/dist/cjs/spreadsheet/csv-streaming.d.ts +19 -0
  183. package/dist/cjs/spreadsheet/csv-streaming.js +188 -0
  184. package/dist/cjs/spreadsheet/csv-streaming.js.map +1 -0
  185. package/dist/cjs/spreadsheet/data-operations.d.cts +115 -0
  186. package/dist/cjs/spreadsheet/data-operations.d.ts +115 -0
  187. package/dist/cjs/spreadsheet/data-operations.js +1515 -0
  188. package/dist/cjs/spreadsheet/data-operations.js.map +1 -0
  189. package/dist/cjs/spreadsheet/deduplication-utils.d.cts +31 -0
  190. package/dist/cjs/spreadsheet/deduplication-utils.d.ts +31 -0
  191. package/dist/cjs/spreadsheet/deduplication-utils.js +65 -0
  192. package/dist/cjs/spreadsheet/deduplication-utils.js.map +1 -0
  193. package/dist/cjs/spreadsheet/range-operations.d.cts +184 -0
  194. package/dist/cjs/spreadsheet/range-operations.d.ts +184 -0
  195. package/dist/cjs/spreadsheet/range-operations.js +672 -0
  196. package/dist/cjs/spreadsheet/range-operations.js.map +1 -0
  197. package/dist/cjs/spreadsheet/sheet-operations.d.cts +30 -0
  198. package/dist/cjs/spreadsheet/sheet-operations.d.ts +30 -0
  199. package/dist/cjs/spreadsheet/sheet-operations.js +811 -0
  200. package/dist/cjs/spreadsheet/sheet-operations.js.map +1 -0
  201. package/dist/cjs/spreadsheet/spreadsheet-management.d.cts +21 -0
  202. package/dist/cjs/spreadsheet/spreadsheet-management.d.ts +21 -0
  203. package/dist/cjs/spreadsheet/spreadsheet-management.js +310 -0
  204. package/dist/cjs/spreadsheet/spreadsheet-management.js.map +1 -0
  205. package/dist/cjs/types.d.cts +53 -0
  206. package/dist/cjs/types.d.ts +53 -0
  207. package/dist/cjs/types.js +5 -0
  208. package/dist/cjs/types.js.map +1 -0
  209. package/dist/esm/constants.d.ts +7 -0
  210. package/dist/esm/constants.js +7 -0
  211. package/dist/esm/constants.js.map +1 -0
  212. package/dist/esm/index.d.ts +8 -0
  213. package/dist/esm/index.js +34 -0
  214. package/dist/esm/index.js.map +1 -0
  215. package/dist/esm/lib/create-store.d.ts +2 -0
  216. package/dist/esm/lib/create-store.js +6 -0
  217. package/dist/esm/lib/create-store.js.map +1 -0
  218. package/dist/esm/mcp/index.d.ts +3 -0
  219. package/dist/esm/mcp/index.js +6 -0
  220. package/dist/esm/mcp/index.js.map +1 -0
  221. package/dist/esm/mcp/prompts/a1-notation.d.ts +19 -0
  222. package/dist/esm/mcp/prompts/a1-notation.js +49 -0
  223. package/dist/esm/mcp/prompts/a1-notation.js.map +1 -0
  224. package/dist/esm/mcp/prompts/index.d.ts +1 -0
  225. package/dist/esm/mcp/prompts/index.js +1 -0
  226. package/dist/esm/mcp/prompts/index.js.map +1 -0
  227. package/dist/esm/mcp/resources/index.d.ts +1 -0
  228. package/dist/esm/mcp/resources/index.js +1 -0
  229. package/dist/esm/mcp/resources/index.js.map +1 -0
  230. package/dist/esm/mcp/resources/spreadsheet.d.ts +2 -0
  231. package/dist/esm/mcp/resources/spreadsheet.js +88 -0
  232. package/dist/esm/mcp/resources/spreadsheet.js.map +1 -0
  233. package/dist/esm/mcp/tools/cells-format.d.ts +144 -0
  234. package/dist/esm/mcp/tools/cells-format.js +288 -0
  235. package/dist/esm/mcp/tools/cells-format.js.map +1 -0
  236. package/dist/esm/mcp/tools/chart-create.d.ts +94 -0
  237. package/dist/esm/mcp/tools/chart-create.js +408 -0
  238. package/dist/esm/mcp/tools/chart-create.js.map +1 -0
  239. package/dist/esm/mcp/tools/columns-get.d.ts +55 -0
  240. package/dist/esm/mcp/tools/columns-get.js +113 -0
  241. package/dist/esm/mcp/tools/columns-get.js.map +1 -0
  242. package/dist/esm/mcp/tools/columns-update.d.ts +86 -0
  243. package/dist/esm/mcp/tools/columns-update.js +296 -0
  244. package/dist/esm/mcp/tools/columns-update.js.map +1 -0
  245. package/dist/esm/mcp/tools/csv-get-columns.d.ts +43 -0
  246. package/dist/esm/mcp/tools/csv-get-columns.js +95 -0
  247. package/dist/esm/mcp/tools/csv-get-columns.js.map +1 -0
  248. package/dist/esm/mcp/tools/dimensions-batch-update.d.ts +118 -0
  249. package/dist/esm/mcp/tools/dimensions-batch-update.js +321 -0
  250. package/dist/esm/mcp/tools/dimensions-batch-update.js.map +1 -0
  251. package/dist/esm/mcp/tools/dimensions-move.d.ts +86 -0
  252. package/dist/esm/mcp/tools/dimensions-move.js +183 -0
  253. package/dist/esm/mcp/tools/dimensions-move.js.map +1 -0
  254. package/dist/esm/mcp/tools/index.d.ts +26 -0
  255. package/dist/esm/mcp/tools/index.js +26 -0
  256. package/dist/esm/mcp/tools/index.js.map +1 -0
  257. package/dist/esm/mcp/tools/lib/dimension-operations.d.ts +48 -0
  258. package/dist/esm/mcp/tools/lib/dimension-operations.js +93 -0
  259. package/dist/esm/mcp/tools/lib/dimension-operations.js.map +1 -0
  260. package/dist/esm/mcp/tools/rows-append.d.ts +58 -0
  261. package/dist/esm/mcp/tools/rows-append.js +151 -0
  262. package/dist/esm/mcp/tools/rows-append.js.map +1 -0
  263. package/dist/esm/mcp/tools/rows-csv-append.d.ts +67 -0
  264. package/dist/esm/mcp/tools/rows-csv-append.js +342 -0
  265. package/dist/esm/mcp/tools/rows-csv-append.js.map +1 -0
  266. package/dist/esm/mcp/tools/rows-get.d.ts +56 -0
  267. package/dist/esm/mcp/tools/rows-get.js +116 -0
  268. package/dist/esm/mcp/tools/rows-get.js.map +1 -0
  269. package/dist/esm/mcp/tools/sheet-copy-to.d.ts +68 -0
  270. package/dist/esm/mcp/tools/sheet-copy-to.js +156 -0
  271. package/dist/esm/mcp/tools/sheet-copy-to.js.map +1 -0
  272. package/dist/esm/mcp/tools/sheet-copy.d.ts +80 -0
  273. package/dist/esm/mcp/tools/sheet-copy.js +177 -0
  274. package/dist/esm/mcp/tools/sheet-copy.js.map +1 -0
  275. package/dist/esm/mcp/tools/sheet-create.d.ts +56 -0
  276. package/dist/esm/mcp/tools/sheet-create.js +110 -0
  277. package/dist/esm/mcp/tools/sheet-create.js.map +1 -0
  278. package/dist/esm/mcp/tools/sheet-delete.d.ts +62 -0
  279. package/dist/esm/mcp/tools/sheet-delete.js +125 -0
  280. package/dist/esm/mcp/tools/sheet-delete.js.map +1 -0
  281. package/dist/esm/mcp/tools/sheet-find.d.ts +48 -0
  282. package/dist/esm/mcp/tools/sheet-find.js +90 -0
  283. package/dist/esm/mcp/tools/sheet-find.js.map +1 -0
  284. package/dist/esm/mcp/tools/sheet-rename.d.ts +60 -0
  285. package/dist/esm/mcp/tools/sheet-rename.js +128 -0
  286. package/dist/esm/mcp/tools/sheet-rename.js.map +1 -0
  287. package/dist/esm/mcp/tools/spreadsheet-copy.d.ts +58 -0
  288. package/dist/esm/mcp/tools/spreadsheet-copy.js +117 -0
  289. package/dist/esm/mcp/tools/spreadsheet-copy.js.map +1 -0
  290. package/dist/esm/mcp/tools/spreadsheet-create.d.ts +52 -0
  291. package/dist/esm/mcp/tools/spreadsheet-create.js +97 -0
  292. package/dist/esm/mcp/tools/spreadsheet-create.js.map +1 -0
  293. package/dist/esm/mcp/tools/spreadsheet-find.d.ts +58 -0
  294. package/dist/esm/mcp/tools/spreadsheet-find.js +113 -0
  295. package/dist/esm/mcp/tools/spreadsheet-find.js.map +1 -0
  296. package/dist/esm/mcp/tools/spreadsheet-rename.d.ts +56 -0
  297. package/dist/esm/mcp/tools/spreadsheet-rename.js +112 -0
  298. package/dist/esm/mcp/tools/spreadsheet-rename.js.map +1 -0
  299. package/dist/esm/mcp/tools/validation-set.d.ts +144 -0
  300. package/dist/esm/mcp/tools/validation-set.js +366 -0
  301. package/dist/esm/mcp/tools/validation-set.js.map +1 -0
  302. package/dist/esm/mcp/tools/values-batch-update.d.ts +102 -0
  303. package/dist/esm/mcp/tools/values-batch-update.js +224 -0
  304. package/dist/esm/mcp/tools/values-batch-update.js.map +1 -0
  305. package/dist/esm/mcp/tools/values-clear.d.ts +56 -0
  306. package/dist/esm/mcp/tools/values-clear.js +131 -0
  307. package/dist/esm/mcp/tools/values-clear.js.map +1 -0
  308. package/dist/esm/mcp/tools/values-csv-update.d.ts +75 -0
  309. package/dist/esm/mcp/tools/values-csv-update.js +202 -0
  310. package/dist/esm/mcp/tools/values-csv-update.js.map +1 -0
  311. package/dist/esm/mcp/tools/values-replace.d.ts +68 -0
  312. package/dist/esm/mcp/tools/values-replace.js +171 -0
  313. package/dist/esm/mcp/tools/values-replace.js.map +1 -0
  314. package/dist/esm/mcp/tools/values-search.d.ts +74 -0
  315. package/dist/esm/mcp/tools/values-search.js +229 -0
  316. package/dist/esm/mcp/tools/values-search.js.map +1 -0
  317. package/dist/esm/package.json +1 -0
  318. package/dist/esm/schemas/index.d.ts +14 -0
  319. package/dist/esm/schemas/index.js +35 -0
  320. package/dist/esm/schemas/index.js.map +1 -0
  321. package/dist/esm/setup/config.d.ts +44 -0
  322. package/dist/esm/setup/config.js +151 -0
  323. package/dist/esm/setup/config.js.map +1 -0
  324. package/dist/esm/setup/http.d.ts +8 -0
  325. package/dist/esm/setup/http.js +54 -0
  326. package/dist/esm/setup/http.js.map +1 -0
  327. package/dist/esm/setup/index.d.ts +5 -0
  328. package/dist/esm/setup/index.js +5 -0
  329. package/dist/esm/setup/index.js.map +1 -0
  330. package/dist/esm/setup/oauth-google.d.ts +54 -0
  331. package/dist/esm/setup/oauth-google.js +142 -0
  332. package/dist/esm/setup/oauth-google.js.map +1 -0
  333. package/dist/esm/setup/runtime.d.ts +10 -0
  334. package/dist/esm/setup/runtime.js +84 -0
  335. package/dist/esm/setup/runtime.js.map +1 -0
  336. package/dist/esm/setup/stdio.d.ts +7 -0
  337. package/dist/esm/setup/stdio.js +38 -0
  338. package/dist/esm/setup/stdio.js.map +1 -0
  339. package/dist/esm/spreadsheet/column-utilities.d.ts +1 -0
  340. package/dist/esm/spreadsheet/column-utilities.js +10 -0
  341. package/dist/esm/spreadsheet/column-utilities.js.map +1 -0
  342. package/dist/esm/spreadsheet/csv-streaming.d.ts +19 -0
  343. package/dist/esm/spreadsheet/csv-streaming.js +43 -0
  344. package/dist/esm/spreadsheet/csv-streaming.js.map +1 -0
  345. package/dist/esm/spreadsheet/data-operations.d.ts +115 -0
  346. package/dist/esm/spreadsheet/data-operations.js +712 -0
  347. package/dist/esm/spreadsheet/data-operations.js.map +1 -0
  348. package/dist/esm/spreadsheet/deduplication-utils.d.ts +31 -0
  349. package/dist/esm/spreadsheet/deduplication-utils.js +54 -0
  350. package/dist/esm/spreadsheet/deduplication-utils.js.map +1 -0
  351. package/dist/esm/spreadsheet/range-operations.d.ts +184 -0
  352. package/dist/esm/spreadsheet/range-operations.js +591 -0
  353. package/dist/esm/spreadsheet/range-operations.js.map +1 -0
  354. package/dist/esm/spreadsheet/sheet-operations.d.ts +30 -0
  355. package/dist/esm/spreadsheet/sheet-operations.js +359 -0
  356. package/dist/esm/spreadsheet/sheet-operations.js.map +1 -0
  357. package/dist/esm/spreadsheet/spreadsheet-management.d.ts +21 -0
  358. package/dist/esm/spreadsheet/spreadsheet-management.js +73 -0
  359. package/dist/esm/spreadsheet/spreadsheet-management.js.map +1 -0
  360. package/dist/esm/types.d.ts +53 -0
  361. package/dist/esm/types.js +1 -0
  362. package/dist/esm/types.js.map +1 -0
  363. package/package.json +108 -0
@@ -0,0 +1,712 @@
1
+ import { a1Col } from './column-utilities.js';
2
+ import { findSheetByRef } from './sheet-operations.js';
3
+ export async function discoverHeader(sheets, spreadsheetId, sheetTitle) {
4
+ try {
5
+ var _response_data;
6
+ const response = await sheets.spreadsheets.values.get({
7
+ spreadsheetId,
8
+ range: `${sheetTitle}!1:1`,
9
+ majorDimension: 'ROWS'
10
+ });
11
+ return (((_response_data = response.data) === null || _response_data === void 0 ? void 0 : _response_data.values) || [])[0] || [];
12
+ } catch {
13
+ return [];
14
+ }
15
+ }
16
+ export function validateAndMapHeaders(sheetHeaders, canonicalHeaders, requiredColumns = []) {
17
+ const normalizeColumn = (col)=>String(col !== null && col !== void 0 ? col : '').toLowerCase().replace(/[^a-z0-9]/g, '');
18
+ const sheetNormalized = sheetHeaders.map(normalizeColumn);
19
+ const canonicalNormalized = canonicalHeaders.map(normalizeColumn);
20
+ const requiredNormalized = requiredColumns.map(normalizeColumn);
21
+ const mappings = [];
22
+ const missingColumns = [];
23
+ const extraColumns = [
24
+ ...sheetHeaders
25
+ ];
26
+ // Create mappings for canonical columns
27
+ canonicalHeaders.forEach((canonical, canonicalIndex)=>{
28
+ const canonicalNorm = canonicalNormalized[canonicalIndex];
29
+ if (!canonicalNorm) return; // Skip if normalization resulted in empty string
30
+ let sheetIndex = sheetNormalized.indexOf(canonicalNorm);
31
+ // Special handling for 'id' -> 'messageid' mapping
32
+ if (sheetIndex === -1 && canonicalNorm === 'id') {
33
+ sheetIndex = sheetNormalized.indexOf('messageid');
34
+ }
35
+ if (sheetIndex !== -1) {
36
+ const sheetHeader = sheetHeaders[sheetIndex];
37
+ if (sheetHeader !== undefined) {
38
+ mappings.push({
39
+ canonical,
40
+ sheet: sheetHeader,
41
+ index: sheetIndex
42
+ });
43
+ // Remove from extra columns
44
+ const extraIndex = extraColumns.indexOf(sheetHeader);
45
+ if (extraIndex !== -1) {
46
+ extraColumns.splice(extraIndex, 1);
47
+ }
48
+ }
49
+ } else if (requiredNormalized.includes(canonicalNorm)) {
50
+ missingColumns.push(canonical);
51
+ }
52
+ });
53
+ return {
54
+ valid: missingColumns.length === 0,
55
+ missingColumns,
56
+ extraColumns,
57
+ mappings
58
+ };
59
+ }
60
+ /** Ensures consistent key generation across all functions */ export function generateRowKey(row, header, strategy) {
61
+ const { keyColumns, useProviderIdLogic, separator = '\\' } = strategy;
62
+ // Normalize header for consistent lookups
63
+ const lowerHeader = header.map((h)=>String(h !== null && h !== void 0 ? h : '').toLowerCase());
64
+ if (useProviderIdLogic) {
65
+ const providerIndex = lowerHeader.indexOf('provider');
66
+ let idIndex = lowerHeader.indexOf('messageid');
67
+ if (idIndex === -1) idIndex = lowerHeader.indexOf('id');
68
+ if (providerIndex >= 0 && idIndex >= 0) {
69
+ var _row_providerIndex, _row_idIndex;
70
+ const providerVal = String((_row_providerIndex = row[providerIndex]) !== null && _row_providerIndex !== void 0 ? _row_providerIndex : '').trim();
71
+ const idVal = String((_row_idIndex = row[idIndex]) !== null && _row_idIndex !== void 0 ? _row_idIndex : '').trim();
72
+ if (providerVal || idVal) {
73
+ // Only return key if at least one component exists
74
+ return [
75
+ providerVal,
76
+ idVal
77
+ ].join(separator);
78
+ }
79
+ }
80
+ }
81
+ // Standard key generation using specified columns
82
+ const keyIndices = keyColumns.map((name)=>{
83
+ const normalizedName = String(name !== null && name !== void 0 ? name : '').toLowerCase();
84
+ let index = lowerHeader.indexOf(normalizedName);
85
+ // Consistent fallback: id -> messageid
86
+ if (index === -1 && normalizedName === 'id') {
87
+ index = lowerHeader.indexOf('messageid');
88
+ }
89
+ return index;
90
+ }).filter((index)=>index >= 0);
91
+ if (keyIndices.length === 0) {
92
+ return ''; // Return empty string for invalid key configurations
93
+ }
94
+ const components = keyIndices.map((index)=>{
95
+ var _row_index;
96
+ return String((_row_index = row[index]) !== null && _row_index !== void 0 ? _row_index : '').trim();
97
+ });
98
+ // Only return key if all components are non-empty
99
+ if (components.every((comp)=>comp.length > 0)) {
100
+ return components.join(separator);
101
+ }
102
+ return '';
103
+ }
104
+ export function validateRowKeys(rows, header, strategy) {
105
+ const keyMap = new Map();
106
+ const duplicateKeys = [];
107
+ rows.forEach((row, index)=>{
108
+ var _keyMap_get;
109
+ const key = generateRowKey(row, header, strategy);
110
+ if (key.replace(/\\+/g, '') === '') return; // Skip empty keys
111
+ if (!keyMap.has(key)) {
112
+ keyMap.set(key, []);
113
+ }
114
+ (_keyMap_get = keyMap.get(key)) === null || _keyMap_get === void 0 ? void 0 : _keyMap_get.push(index);
115
+ });
116
+ // Find duplicates
117
+ keyMap.forEach((indices, key)=>{
118
+ if (indices.length > 1) {
119
+ duplicateKeys.push(key);
120
+ }
121
+ });
122
+ return {
123
+ valid: duplicateKeys.length === 0,
124
+ duplicateKeys,
125
+ keyMap
126
+ };
127
+ }
128
+ export async function appendRows(sheets, { spreadsheetId, sheetTitle, sheetRef, rows = [], keySet = null, keyColumns = [
129
+ 'id'
130
+ ], header = [], logger }) {
131
+ if (!sheets) throw new Error('appendRows: sheets is required');
132
+ if (!spreadsheetId) throw new Error('appendRows: spreadsheetId is required');
133
+ if (!sheetTitle && !sheetRef) throw new Error('appendRows: either sheetTitle or sheetRef is required');
134
+ // Resolve the actual sheet title from sheetRef if provided
135
+ let resolvedSheetTitle = sheetTitle;
136
+ if (sheetRef) {
137
+ const sheet = await findSheetByRef(sheets, spreadsheetId, sheetRef, logger);
138
+ if (sheet) {
139
+ var _sheet_properties;
140
+ resolvedSheetTitle = ((_sheet_properties = sheet.properties) === null || _sheet_properties === void 0 ? void 0 : _sheet_properties.title) || sheetRef;
141
+ } else {
142
+ // Sheet doesn't exist, use the sheetRef as the title
143
+ resolvedSheetTitle = sheetRef;
144
+ }
145
+ }
146
+ if (!resolvedSheetTitle) throw new Error('appendRows: could not resolve sheet title');
147
+ if (!Array.isArray(rows) || rows.length === 0) return {
148
+ updatedRows: 0,
149
+ inserted: []
150
+ };
151
+ if (!Array.isArray(header) || header.length === 0) {
152
+ const respHeader = await sheets.spreadsheets.values.get({
153
+ spreadsheetId,
154
+ range: `${resolvedSheetTitle}!1:1`,
155
+ majorDimension: 'ROWS'
156
+ });
157
+ const vr = respHeader.data;
158
+ header = ((vr === null || vr === void 0 ? void 0 : vr.values) || [])[0] || [];
159
+ }
160
+ const resolveKeyIndices = (kc, hdr)=>{
161
+ if (!Array.isArray(kc) || kc.length === 0) return [];
162
+ for (const c of kc){
163
+ if (typeof c !== 'string' || c.length === 0) throw new Error('appendRows: keyColumns must be an array of non-empty strings');
164
+ }
165
+ if (!Array.isArray(hdr) || hdr.length === 0) {
166
+ throw new Error('appendRows: header array is required when keyColumns are header names');
167
+ }
168
+ return kc.map((name)=>{
169
+ const idx = hdr.indexOf(name);
170
+ if (idx === -1) throw new Error(`appendRows: header name "${name}" not found in header`);
171
+ return idx;
172
+ });
173
+ };
174
+ const keyColsIdx = resolveKeyIndices(keyColumns, header);
175
+ // Internal batch size to avoid Google Sheets limits
176
+ const batchSize = 50;
177
+ if (!keyColsIdx || keyColsIdx.length === 0) {
178
+ let totalUpdated = 0;
179
+ for(let i = 0; i < rows.length; i += batchSize){
180
+ var _app_updates;
181
+ const batch = rows.slice(i, i + batchSize);
182
+ const resp = await sheets.spreadsheets.values.append({
183
+ spreadsheetId,
184
+ range: `${resolvedSheetTitle}!A1`,
185
+ valueInputOption: 'RAW',
186
+ insertDataOption: 'INSERT_ROWS',
187
+ requestBody: {
188
+ values: batch
189
+ }
190
+ });
191
+ const app = resp.data;
192
+ const updatedRows = Number((app === null || app === void 0 ? void 0 : (_app_updates = app.updates) === null || _app_updates === void 0 ? void 0 : _app_updates.updatedRows) || batch.length);
193
+ totalUpdated += updatedRows;
194
+ }
195
+ return {
196
+ updatedRows: totalUpdated,
197
+ inserted: [],
198
+ rowsSkipped: 0
199
+ };
200
+ }
201
+ const toKey = (r)=>{
202
+ const row = r;
203
+ // Use consistent key generation strategy
204
+ const strategy = {
205
+ keyColumns,
206
+ useProviderIdLogic: true,
207
+ separator: '\\'
208
+ };
209
+ return generateRowKey(row, header, strategy);
210
+ };
211
+ const rowsToInsert = [];
212
+ const insertedKeys = [];
213
+ for (const r of rows){
214
+ const key = toKey(r);
215
+ if (keySet && keySet.has(key)) continue;
216
+ rowsToInsert.push(r);
217
+ insertedKeys.push(key);
218
+ }
219
+ if (rowsToInsert.length === 0) {
220
+ const rowsSkipped = rows.length - rowsToInsert.length; // Should be rows.length when all are skipped
221
+ return {
222
+ updatedRows: 0,
223
+ inserted: [],
224
+ rowsSkipped
225
+ };
226
+ }
227
+ // Use smaller internal batch size to avoid Google Sheets character limit errors
228
+ // Especially important when dealing with emails that may have long bodies
229
+ const INTERNAL_BATCH_SIZE = 50;
230
+ let totalUpdated = 0;
231
+ for(let i = 0; i < rowsToInsert.length; i += INTERNAL_BATCH_SIZE){
232
+ const batch = rowsToInsert.slice(i, i + INTERNAL_BATCH_SIZE);
233
+ try {
234
+ var _app2_updates;
235
+ const resp = await sheets.spreadsheets.values.append({
236
+ spreadsheetId,
237
+ range: `${resolvedSheetTitle}!A1`,
238
+ valueInputOption: 'RAW',
239
+ insertDataOption: 'INSERT_ROWS',
240
+ requestBody: {
241
+ values: batch
242
+ }
243
+ });
244
+ const app2 = resp.data;
245
+ const updatedRows = Number((app2 === null || app2 === void 0 ? void 0 : (_app2_updates = app2.updates) === null || _app2_updates === void 0 ? void 0 : _app2_updates.updatedRows) || batch.length);
246
+ totalUpdated += updatedRows;
247
+ } catch (error) {
248
+ // If a batch fails, try with smaller batches to handle partial success
249
+ if (batch.length > 1) {
250
+ for (const singleRow of batch){
251
+ try {
252
+ var _singleApp_updates;
253
+ const singleResp = await sheets.spreadsheets.values.append({
254
+ spreadsheetId,
255
+ range: `${resolvedSheetTitle}!A1`,
256
+ valueInputOption: 'RAW',
257
+ insertDataOption: 'INSERT_ROWS',
258
+ requestBody: {
259
+ values: [
260
+ singleRow
261
+ ]
262
+ }
263
+ });
264
+ const singleApp = singleResp.data;
265
+ const singleUpdatedRows = Number((singleApp === null || singleApp === void 0 ? void 0 : (_singleApp_updates = singleApp.updates) === null || _singleApp_updates === void 0 ? void 0 : _singleApp_updates.updatedRows) || 1);
266
+ totalUpdated += singleUpdatedRows;
267
+ } catch (singleError) {
268
+ var // Skip problematic individual rows but continue processing
269
+ _logger_warn;
270
+ (_logger_warn = logger.warn) === null || _logger_warn === void 0 ? void 0 : _logger_warn.call(logger, `Failed to insert single row: ${singleError instanceof Error ? singleError.message : String(singleError)}`);
271
+ }
272
+ }
273
+ } else {
274
+ var // Single row batch failed, skip it
275
+ _logger_warn1;
276
+ (_logger_warn1 = logger.warn) === null || _logger_warn1 === void 0 ? void 0 : _logger_warn1.call(logger, `Failed to insert batch: ${error instanceof Error ? error.message : String(error)}`);
277
+ }
278
+ }
279
+ }
280
+ const rowsSkipped = rows.length - rowsToInsert.length;
281
+ return {
282
+ updatedRows: totalUpdated,
283
+ inserted: insertedKeys,
284
+ rowsSkipped
285
+ };
286
+ }
287
+ export function mapRowsToHeader({ rows = [], header = [], canonical = [] }) {
288
+ if (!Array.isArray(rows) || rows.length === 0) return [];
289
+ if (!Array.isArray(header) || header.length === 0) return rows;
290
+ if (!Array.isArray(canonical) || canonical.length === 0) return rows;
291
+ const validation = validateAndMapHeaders(header, canonical);
292
+ const mappingLookup = new Map(validation.mappings.map((m)=>[
293
+ m.canonical,
294
+ m.index
295
+ ]));
296
+ return rows.map((row)=>{
297
+ // Fill with null to skip unmapped columns (preserve existing values)
298
+ // Use '' (empty string) only when explicitly wanting to clear a cell
299
+ const mappedRow = new Array(header.length).fill(null);
300
+ canonical.forEach((canonicalCol, canonicalIndex)=>{
301
+ const sheetIndex = mappingLookup.get(canonicalCol);
302
+ if (sheetIndex !== undefined && canonicalIndex < row.length) {
303
+ // Preserve null values - they signal "skip this cell"
304
+ mappedRow[sheetIndex] = row[canonicalIndex];
305
+ }
306
+ });
307
+ return mappedRow;
308
+ });
309
+ }
310
+ export async function snapshotHeaderAndKeys(sheets, spreadsheetId, sheetTitle, keyColumns = [
311
+ 'id'
312
+ ], keyStrategy) {
313
+ var _ref, _ref1;
314
+ const header = await discoverHeader(sheets, spreadsheetId, sheetTitle);
315
+ const keySet = new Set();
316
+ if (header.length === 0) {
317
+ return {
318
+ header,
319
+ keySet,
320
+ keyIndices: []
321
+ };
322
+ }
323
+ const strategy = {
324
+ keyColumns,
325
+ useProviderIdLogic: (_ref = keyStrategy === null || keyStrategy === void 0 ? void 0 : keyStrategy.useProviderIdLogic) !== null && _ref !== void 0 ? _ref : true,
326
+ separator: (_ref1 = keyStrategy === null || keyStrategy === void 0 ? void 0 : keyStrategy.separator) !== null && _ref1 !== void 0 ? _ref1 : '\\'
327
+ };
328
+ // Find key column indices
329
+ const keyIndices = keyColumns.map((name)=>{
330
+ const normalizedName = String(name !== null && name !== void 0 ? name : '').toLowerCase();
331
+ const lowerHeader = header.map((h)=>String(h !== null && h !== void 0 ? h : '').toLowerCase());
332
+ let index = lowerHeader.indexOf(normalizedName);
333
+ if (index === -1 && normalizedName === 'id') {
334
+ index = lowerHeader.indexOf('messageid');
335
+ }
336
+ return index;
337
+ }).filter((index)=>index >= 0);
338
+ if (keyIndices.length === 0) {
339
+ return {
340
+ header,
341
+ keySet,
342
+ keyIndices
343
+ };
344
+ }
345
+ // Read key columns data in chunks
346
+ const chunkSize = 1000;
347
+ let startRow = 2;
348
+ const minIndex = Math.min(...keyIndices);
349
+ const maxIndex = Math.max(...keyIndices);
350
+ const startCol = a1Col(minIndex + 1);
351
+ const endCol = a1Col(maxIndex + 1);
352
+ while(true){
353
+ const endRow = startRow + chunkSize - 1;
354
+ const range = `${sheetTitle}!${startCol}${startRow}:${endCol}${endRow}`;
355
+ try {
356
+ var _response_data;
357
+ const response = await sheets.spreadsheets.values.get({
358
+ spreadsheetId,
359
+ range,
360
+ majorDimension: 'ROWS'
361
+ });
362
+ const rows = ((_response_data = response.data) === null || _response_data === void 0 ? void 0 : _response_data.values) || [];
363
+ if (rows.length === 0) break;
364
+ for (const rawRow of rows){
365
+ // Reconstruct full row for key generation
366
+ const fullRow = new Array(header.length).fill('');
367
+ keyIndices.forEach((globalIndex, _localIndex)=>{
368
+ const localRowIndex = globalIndex - minIndex;
369
+ if (localRowIndex >= 0 && localRowIndex < rawRow.length) {
370
+ fullRow[globalIndex] = rawRow[localRowIndex];
371
+ }
372
+ });
373
+ const key = generateRowKey(fullRow, header, strategy);
374
+ if (key.replace(/\\+/g, '') !== '') {
375
+ keySet.add(key);
376
+ }
377
+ }
378
+ startRow += rows.length;
379
+ if (rows.length < chunkSize) break; // Last chunk
380
+ } catch {
381
+ break; // End of data or error
382
+ }
383
+ }
384
+ return {
385
+ header,
386
+ keySet,
387
+ keyIndices
388
+ };
389
+ }
390
+ /** Tracks row positions for updates in addition to keys */ export async function snapshotHeaderKeysAndPositions(sheets, spreadsheetId, sheetTitle, keyColumns = [
391
+ 'id'
392
+ ], keyStrategy) {
393
+ var _ref, _ref1;
394
+ const header = await discoverHeader(sheets, spreadsheetId, sheetTitle);
395
+ const keySet = new Set();
396
+ const keyToRowMap = new Map();
397
+ if (header.length === 0) {
398
+ return {
399
+ header,
400
+ keySet,
401
+ keyToRowMap,
402
+ keyIndices: []
403
+ };
404
+ }
405
+ const strategy = {
406
+ keyColumns,
407
+ useProviderIdLogic: (_ref = keyStrategy === null || keyStrategy === void 0 ? void 0 : keyStrategy.useProviderIdLogic) !== null && _ref !== void 0 ? _ref : true,
408
+ separator: (_ref1 = keyStrategy === null || keyStrategy === void 0 ? void 0 : keyStrategy.separator) !== null && _ref1 !== void 0 ? _ref1 : '\\'
409
+ };
410
+ // Find key column indices
411
+ const keyIndices = keyColumns.map((name)=>{
412
+ const normalizedName = String(name !== null && name !== void 0 ? name : '').toLowerCase();
413
+ const lowerHeader = header.map((h)=>String(h !== null && h !== void 0 ? h : '').toLowerCase());
414
+ let index = lowerHeader.indexOf(normalizedName);
415
+ if (index === -1 && normalizedName === 'id') {
416
+ index = lowerHeader.indexOf('messageid');
417
+ }
418
+ return index;
419
+ }).filter((index)=>index >= 0);
420
+ if (keyIndices.length === 0) {
421
+ return {
422
+ header,
423
+ keySet,
424
+ keyToRowMap,
425
+ keyIndices
426
+ };
427
+ }
428
+ // Read key columns data in chunks and track row positions
429
+ const chunkSize = 1000;
430
+ let startRow = 2; // Start from row 2 (after header)
431
+ const minIndex = Math.min(...keyIndices);
432
+ const maxIndex = Math.max(...keyIndices);
433
+ const startCol = a1Col(minIndex + 1);
434
+ const endCol = a1Col(maxIndex + 1);
435
+ while(true){
436
+ const endRow = startRow + chunkSize - 1;
437
+ const range = `${sheetTitle}!${startCol}${startRow}:${endCol}${endRow}`;
438
+ try {
439
+ var _response_data;
440
+ const response = await sheets.spreadsheets.values.get({
441
+ spreadsheetId,
442
+ range,
443
+ majorDimension: 'ROWS'
444
+ });
445
+ const rows = ((_response_data = response.data) === null || _response_data === void 0 ? void 0 : _response_data.values) || [];
446
+ if (rows.length === 0) break;
447
+ for(let localRowIndex = 0; localRowIndex < rows.length; localRowIndex++){
448
+ const rawRow = rows[localRowIndex];
449
+ const globalRowNumber = startRow + localRowIndex;
450
+ // Reconstruct full row for key generation
451
+ const fullRow = new Array(header.length).fill('');
452
+ if (rawRow) {
453
+ keyIndices.forEach((globalIndex, _localIndex)=>{
454
+ const localRowArrayIndex = globalIndex - minIndex;
455
+ if (localRowArrayIndex >= 0 && localRowArrayIndex < rawRow.length) {
456
+ fullRow[globalIndex] = rawRow[localRowArrayIndex];
457
+ }
458
+ });
459
+ }
460
+ const key = generateRowKey(fullRow, header, strategy);
461
+ if (key.replace(/\\+/g, '') !== '') {
462
+ keySet.add(key);
463
+ keyToRowMap.set(key, globalRowNumber); // Store 1-indexed row number
464
+ }
465
+ }
466
+ startRow += rows.length;
467
+ if (rows.length < chunkSize) break; // Last chunk
468
+ } catch {
469
+ break; // End of data or error
470
+ }
471
+ }
472
+ return {
473
+ header,
474
+ keySet,
475
+ keyToRowMap,
476
+ keyIndices
477
+ };
478
+ }
479
+ /**
480
+ * Partitions data into updates vs appends based on existing keys with row position tracking
481
+ */ export function partitionDataForUpsert(rows, header, keyStrategy, existingKeys, allowUpdates = false, keyToRowMap) {
482
+ const toAppend = [];
483
+ const toUpdate = [];
484
+ const skippedKeys = [];
485
+ rows.forEach((row)=>{
486
+ const key = generateRowKey(row, header, keyStrategy);
487
+ if (key.replace(/\\+/g, '') === '') {
488
+ // Skip rows with empty keys
489
+ return;
490
+ }
491
+ if (existingKeys.has(key)) {
492
+ if (allowUpdates && keyToRowMap) {
493
+ const existingRowIndex = keyToRowMap.get(key);
494
+ if (existingRowIndex !== undefined) {
495
+ toUpdate.push({
496
+ row,
497
+ existingRowIndex
498
+ });
499
+ } else {
500
+ skippedKeys.push(key);
501
+ }
502
+ } else {
503
+ skippedKeys.push(key);
504
+ }
505
+ } else {
506
+ toAppend.push(row);
507
+ }
508
+ });
509
+ return {
510
+ toAppend,
511
+ toUpdate,
512
+ skippedKeys
513
+ };
514
+ }
515
+ /**
516
+ * Performs batch updates on existing rows using batchUpdate API
517
+ */ export async function performBatchUpdates(sheets, spreadsheetId, sheetTitle, updates, header, batchSize, valueInputOption) {
518
+ const errors = [];
519
+ let totalUpdated = 0;
520
+ // Process updates in batches
521
+ for(let i = 0; i < updates.length; i += batchSize){
522
+ const batch = updates.slice(i, i + batchSize);
523
+ try {
524
+ const requests = [];
525
+ for (const { row, existingRowIndex } of batch){
526
+ requests.push({
527
+ updateCells: {
528
+ range: {
529
+ sheetId: 0,
530
+ startRowIndex: existingRowIndex - 1,
531
+ endRowIndex: existingRowIndex,
532
+ startColumnIndex: 0,
533
+ endColumnIndex: header.length
534
+ },
535
+ rows: [
536
+ {
537
+ values: row.map((cellValue)=>({
538
+ userEnteredValue: {
539
+ stringValue: String(cellValue !== null && cellValue !== void 0 ? cellValue : '')
540
+ }
541
+ }))
542
+ }
543
+ ],
544
+ fields: 'userEnteredValue'
545
+ }
546
+ });
547
+ }
548
+ if (requests.length > 0) {
549
+ await sheets.spreadsheets.batchUpdate({
550
+ spreadsheetId,
551
+ requestBody: {
552
+ requests
553
+ }
554
+ });
555
+ totalUpdated += batch.length;
556
+ }
557
+ } catch (error) {
558
+ const errorMsg = `Batch update ${Math.floor(i / batchSize) + 1} failed: ${error instanceof Error ? error.message : String(error)}`;
559
+ errors.push(errorMsg);
560
+ // Try individual updates for failed batches
561
+ for (const { row, existingRowIndex } of batch){
562
+ try {
563
+ const range = `${sheetTitle}!A${existingRowIndex}:${a1Col(header.length)}${existingRowIndex}`;
564
+ await sheets.spreadsheets.values.update({
565
+ spreadsheetId,
566
+ range,
567
+ valueInputOption,
568
+ requestBody: {
569
+ values: [
570
+ row
571
+ ]
572
+ }
573
+ });
574
+ totalUpdated += 1;
575
+ } catch (singleError) {
576
+ errors.push(`Failed to update row ${existingRowIndex}: ${singleError instanceof Error ? singleError.message : String(singleError)}`);
577
+ }
578
+ }
579
+ }
580
+ }
581
+ const result = {
582
+ updatedRows: totalUpdated
583
+ };
584
+ if (errors.length > 0) {
585
+ result.errors = errors;
586
+ }
587
+ return result;
588
+ }
589
+ export async function upsertByKey(sheets, { spreadsheetId, sheetTitle, sheetRef, rows, canonicalHeaders, options, logger }) {
590
+ // Validate inputs
591
+ if (!sheets) throw new Error('upsertByKey: sheets client is required');
592
+ if (!spreadsheetId) throw new Error('upsertByKey: spreadsheetId is required');
593
+ if (!sheetTitle && !sheetRef) throw new Error('upsertByKey: either sheetTitle or sheetRef is required');
594
+ if (!Array.isArray(rows) || rows.length === 0) {
595
+ return {
596
+ updatedRows: 0,
597
+ inserted: [],
598
+ rowsSkipped: 0
599
+ };
600
+ }
601
+ // Step 1: Input validation (duplicate key checking)
602
+ let resolvedSheetTitle = sheetTitle;
603
+ if (sheetRef) {
604
+ var _sheet_properties;
605
+ const sheet = await findSheetByRef(sheets, spreadsheetId, sheetRef, logger);
606
+ resolvedSheetTitle = (sheet === null || sheet === void 0 ? void 0 : (_sheet_properties = sheet.properties) === null || _sheet_properties === void 0 ? void 0 : _sheet_properties.title) || sheetRef;
607
+ }
608
+ if (!resolvedSheetTitle) {
609
+ throw new Error('upsertByKey: could not resolve sheet title');
610
+ }
611
+ // Validate for duplicate keys in input data
612
+ const inputValidation = validateRowKeys(rows, canonicalHeaders || [], options.keyStrategy);
613
+ if (!inputValidation.valid) {
614
+ throw new Error(`upsertByKey: duplicate keys found in input data: ${inputValidation.duplicateKeys.join(', ')}`);
615
+ }
616
+ // Step 2: Header discovery and column mapping
617
+ const currentHeader = await discoverHeader(sheets, spreadsheetId, resolvedSheetTitle);
618
+ let effectiveHeader = currentHeader;
619
+ // If sheet is empty and we have canonical headers, use them
620
+ if (currentHeader.length === 0 && canonicalHeaders && canonicalHeaders.length > 0) {
621
+ effectiveHeader = canonicalHeaders;
622
+ // Write headers to sheet
623
+ await sheets.spreadsheets.values.append({
624
+ spreadsheetId,
625
+ range: `${resolvedSheetTitle}!A1`,
626
+ valueInputOption: options.valueInputOption || 'USER_ENTERED',
627
+ insertDataOption: 'INSERT_ROWS',
628
+ requestBody: {
629
+ values: [
630
+ effectiveHeader
631
+ ]
632
+ }
633
+ });
634
+ }
635
+ // Validate headers if we have requirements
636
+ if (canonicalHeaders && canonicalHeaders.length > 0) {
637
+ const headerValidation = validateAndMapHeaders(effectiveHeader, canonicalHeaders);
638
+ if (!headerValidation.valid) {
639
+ throw new Error(`upsertByKey: missing required columns: ${headerValidation.missingColumns.join(', ')}`);
640
+ }
641
+ }
642
+ // Step 3: Key column reading for existing row lookup with position tracking
643
+ const { keySet: existingKeys, keyToRowMap } = await snapshotHeaderKeysAndPositions(sheets, spreadsheetId, resolvedSheetTitle, options.keyStrategy.keyColumns, options.keyStrategy);
644
+ // Step 4: Partition changes (updates vs appends)
645
+ let processedRows = rows;
646
+ // Map canonical data to sheet structure if needed
647
+ if (canonicalHeaders && canonicalHeaders.length > 0 && effectiveHeader.length > 0) {
648
+ processedRows = mapRowsToHeader({
649
+ rows,
650
+ header: effectiveHeader,
651
+ canonical: canonicalHeaders
652
+ });
653
+ }
654
+ const partition = partitionDataForUpsert(processedRows, effectiveHeader, options.keyStrategy, existingKeys, options.allowUpdates, keyToRowMap);
655
+ // Step 5: Efficient batch writing
656
+ const batchSize = options.batchSize || 50;
657
+ const errors = [];
658
+ let totalUpdated = 0;
659
+ const insertedKeys = [];
660
+ // Handle appends with proper error handling and partial success tracking
661
+ if (partition.toAppend.length > 0) {
662
+ for(let i = 0; i < partition.toAppend.length; i += batchSize){
663
+ const batch = partition.toAppend.slice(i, i + batchSize);
664
+ try {
665
+ var _response_data_updates, _response_data;
666
+ const response = await sheets.spreadsheets.values.append({
667
+ spreadsheetId,
668
+ range: `${resolvedSheetTitle}!A1`,
669
+ valueInputOption: options.valueInputOption || 'USER_ENTERED',
670
+ insertDataOption: 'INSERT_ROWS',
671
+ requestBody: {
672
+ values: batch
673
+ }
674
+ });
675
+ const updatedRows = Number(((_response_data = response.data) === null || _response_data === void 0 ? void 0 : (_response_data_updates = _response_data.updates) === null || _response_data_updates === void 0 ? void 0 : _response_data_updates.updatedRows) || batch.length);
676
+ totalUpdated += updatedRows;
677
+ // Track inserted keys for successful batch
678
+ batch.forEach((row)=>{
679
+ const key = generateRowKey(row, effectiveHeader, options.keyStrategy);
680
+ if (key.replace(/\\+/g, '') !== '') {
681
+ insertedKeys.push(key);
682
+ }
683
+ });
684
+ } catch (error) {
685
+ const errorMsg = `Batch ${Math.floor(i / batchSize) + 1} append failed: ${error instanceof Error ? error.message : String(error)}`;
686
+ errors.push(errorMsg);
687
+ }
688
+ }
689
+ }
690
+ // Handle updates with proper row position tracking
691
+ if (partition.toUpdate.length > 0 && options.allowUpdates) {
692
+ try {
693
+ const updateResult = await performBatchUpdates(sheets, spreadsheetId, resolvedSheetTitle, partition.toUpdate, effectiveHeader, batchSize, options.valueInputOption || 'USER_ENTERED');
694
+ totalUpdated += updateResult.updatedRows;
695
+ if (updateResult.errors) {
696
+ errors.push(...updateResult.errors);
697
+ }
698
+ } catch (updateError) {
699
+ const errorMsg = `Update operations failed: ${updateError instanceof Error ? updateError.message : String(updateError)}`;
700
+ errors.push(errorMsg);
701
+ }
702
+ }
703
+ const result = {
704
+ updatedRows: totalUpdated,
705
+ inserted: insertedKeys,
706
+ rowsSkipped: partition.skippedKeys.length
707
+ };
708
+ if (errors.length > 0) {
709
+ result.errors = errors;
710
+ }
711
+ return result;
712
+ }