digital-tools 2.1.3 → 2.4.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 (294) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +19 -0
  3. package/README.md +2 -0
  4. package/dist/client.d.ts +109 -0
  5. package/dist/client.d.ts.map +1 -0
  6. package/dist/client.js +69 -0
  7. package/dist/client.js.map +1 -0
  8. package/dist/define.d.ts +2 -2
  9. package/dist/define.d.ts.map +1 -1
  10. package/dist/define.js +21 -11
  11. package/dist/define.js.map +1 -1
  12. package/dist/function-ref.d.ts +229 -0
  13. package/dist/function-ref.d.ts.map +1 -0
  14. package/dist/function-ref.js +28 -0
  15. package/dist/function-ref.js.map +1 -0
  16. package/dist/function-sugar.d.ts +57 -0
  17. package/dist/function-sugar.d.ts.map +1 -0
  18. package/dist/function-sugar.js +79 -0
  19. package/dist/function-sugar.js.map +1 -0
  20. package/dist/index.d.ts +10 -3
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +24 -4
  23. package/dist/index.js.map +1 -1
  24. package/dist/providers/analytics/mixpanel.d.ts.map +1 -1
  25. package/dist/providers/analytics/mixpanel.js +21 -18
  26. package/dist/providers/analytics/mixpanel.js.map +1 -1
  27. package/dist/providers/calendar/cal-com.d.ts.map +1 -1
  28. package/dist/providers/calendar/cal-com.js +10 -10
  29. package/dist/providers/calendar/cal-com.js.map +1 -1
  30. package/dist/providers/calendar/google-calendar.d.ts.map +1 -1
  31. package/dist/providers/calendar/google-calendar.js +4 -4
  32. package/dist/providers/calendar/google-calendar.js.map +1 -1
  33. package/dist/providers/crm/hubspot.d.ts.map +1 -1
  34. package/dist/providers/crm/hubspot.js +107 -85
  35. package/dist/providers/crm/hubspot.js.map +1 -1
  36. package/dist/providers/development/github.d.ts.map +1 -1
  37. package/dist/providers/development/github.js +40 -43
  38. package/dist/providers/development/github.js.map +1 -1
  39. package/dist/providers/ecommerce/shopify.d.ts.map +1 -1
  40. package/dist/providers/ecommerce/shopify.js +79 -62
  41. package/dist/providers/ecommerce/shopify.js.map +1 -1
  42. package/dist/providers/email/resend.d.ts.map +1 -1
  43. package/dist/providers/email/resend.js +20 -16
  44. package/dist/providers/email/resend.js.map +1 -1
  45. package/dist/providers/email/sendgrid.d.ts.map +1 -1
  46. package/dist/providers/email/sendgrid.js +12 -9
  47. package/dist/providers/email/sendgrid.js.map +1 -1
  48. package/dist/providers/finance/stripe.d.ts.map +1 -1
  49. package/dist/providers/finance/stripe.js +44 -42
  50. package/dist/providers/finance/stripe.js.map +1 -1
  51. package/dist/providers/forms/typeform.d.ts.map +1 -1
  52. package/dist/providers/forms/typeform.js +68 -58
  53. package/dist/providers/forms/typeform.js.map +1 -1
  54. package/dist/providers/knowledge/notion.d.ts.map +1 -1
  55. package/dist/providers/knowledge/notion.js +75 -41
  56. package/dist/providers/knowledge/notion.js.map +1 -1
  57. package/dist/providers/marketing/mailchimp.d.ts.map +1 -1
  58. package/dist/providers/marketing/mailchimp.js +74 -61
  59. package/dist/providers/marketing/mailchimp.js.map +1 -1
  60. package/dist/providers/media/cloudinary.d.ts.map +1 -1
  61. package/dist/providers/media/cloudinary.js +30 -28
  62. package/dist/providers/media/cloudinary.js.map +1 -1
  63. package/dist/providers/messaging/slack.d.ts.map +1 -1
  64. package/dist/providers/messaging/slack.js +75 -58
  65. package/dist/providers/messaging/slack.js.map +1 -1
  66. package/dist/providers/messaging/twilio-sms.d.ts.map +1 -1
  67. package/dist/providers/messaging/twilio-sms.js +33 -15
  68. package/dist/providers/messaging/twilio-sms.js.map +1 -1
  69. package/dist/providers/project-management/linear.d.ts.map +1 -1
  70. package/dist/providers/project-management/linear.js +31 -27
  71. package/dist/providers/project-management/linear.js.map +1 -1
  72. package/dist/providers/spreadsheet/google-sheets.d.ts.map +1 -1
  73. package/dist/providers/spreadsheet/google-sheets.js +21 -18
  74. package/dist/providers/spreadsheet/google-sheets.js.map +1 -1
  75. package/dist/providers/spreadsheet/xlsx.d.ts.map +1 -1
  76. package/dist/providers/spreadsheet/xlsx.js +4 -4
  77. package/dist/providers/spreadsheet/xlsx.js.map +1 -1
  78. package/dist/providers/storage/index.js +1 -0
  79. package/dist/providers/storage/index.js.map +1 -1
  80. package/dist/providers/storage/s3.d.ts.map +1 -1
  81. package/dist/providers/storage/s3.js +36 -27
  82. package/dist/providers/storage/s3.js.map +1 -1
  83. package/dist/providers/support/zendesk.d.ts.map +1 -1
  84. package/dist/providers/support/zendesk.js +24 -25
  85. package/dist/providers/support/zendesk.js.map +1 -1
  86. package/dist/providers/tasks/todoist.d.ts.map +1 -1
  87. package/dist/providers/tasks/todoist.js +18 -18
  88. package/dist/providers/tasks/todoist.js.map +1 -1
  89. package/dist/providers/video-conferencing/google-meet.d.ts.map +1 -1
  90. package/dist/providers/video-conferencing/google-meet.js +11 -11
  91. package/dist/providers/video-conferencing/google-meet.js.map +1 -1
  92. package/dist/providers/video-conferencing/jitsi.js +14 -14
  93. package/dist/providers/video-conferencing/jitsi.js.map +1 -1
  94. package/dist/providers/video-conferencing/teams.d.ts.map +1 -1
  95. package/dist/providers/video-conferencing/teams.js +9 -7
  96. package/dist/providers/video-conferencing/teams.js.map +1 -1
  97. package/dist/providers/video-conferencing/zoom.d.ts.map +1 -1
  98. package/dist/providers/video-conferencing/zoom.js +26 -24
  99. package/dist/providers/video-conferencing/zoom.js.map +1 -1
  100. package/dist/tools/data.d.ts.map +1 -1
  101. package/dist/tools/data.js +5 -12
  102. package/dist/tools/data.js.map +1 -1
  103. package/dist/tools/index.d.ts +1 -0
  104. package/dist/tools/index.d.ts.map +1 -1
  105. package/dist/tools/index.js +1 -0
  106. package/dist/tools/index.js.map +1 -1
  107. package/dist/tools/system.d.ts +289 -0
  108. package/dist/tools/system.d.ts.map +1 -0
  109. package/dist/tools/system.js +752 -0
  110. package/dist/tools/system.js.map +1 -0
  111. package/dist/tools/web.d.ts.map +1 -1
  112. package/dist/tools/web.js +22 -10
  113. package/dist/tools/web.js.map +1 -1
  114. package/dist/track-record.d.ts +101 -0
  115. package/dist/track-record.d.ts.map +1 -0
  116. package/dist/track-record.js +17 -0
  117. package/dist/track-record.js.map +1 -0
  118. package/dist/types.d.ts +210 -9
  119. package/dist/types.d.ts.map +1 -1
  120. package/dist/verb-registration.d.ts +122 -0
  121. package/dist/verb-registration.d.ts.map +1 -0
  122. package/dist/verb-registration.js +176 -0
  123. package/dist/verb-registration.js.map +1 -0
  124. package/dist/worker.d.ts +93 -0
  125. package/dist/worker.d.ts.map +1 -0
  126. package/dist/worker.js +315 -0
  127. package/dist/worker.js.map +1 -0
  128. package/dist/wrap.d.ts +89 -0
  129. package/dist/wrap.d.ts.map +1 -0
  130. package/dist/wrap.js +225 -0
  131. package/dist/wrap.js.map +1 -0
  132. package/package.json +31 -14
  133. package/src/client.ts +136 -0
  134. package/src/define.ts +30 -24
  135. package/src/function-ref.ts +264 -0
  136. package/src/function-sugar.ts +134 -0
  137. package/src/index.ts +132 -10
  138. package/src/providers/analytics/mixpanel.ts +19 -18
  139. package/src/providers/calendar/cal-com.ts +29 -18
  140. package/src/providers/calendar/google-calendar.ts +20 -14
  141. package/src/providers/crm/hubspot.ts +225 -99
  142. package/src/providers/development/github.ts +206 -135
  143. package/src/providers/ecommerce/shopify.ts +250 -89
  144. package/src/providers/email/resend.ts +101 -28
  145. package/src/providers/email/sendgrid.ts +12 -9
  146. package/src/providers/finance/stripe.ts +128 -49
  147. package/src/providers/forms/typeform.ts +74 -58
  148. package/src/providers/knowledge/notion.ts +340 -88
  149. package/src/providers/marketing/mailchimp.ts +86 -70
  150. package/src/providers/media/cloudinary.ts +99 -41
  151. package/src/providers/messaging/slack.ts +283 -85
  152. package/src/providers/messaging/twilio-sms.ts +35 -15
  153. package/src/providers/project-management/linear.ts +143 -55
  154. package/src/providers/spreadsheet/google-sheets.ts +222 -56
  155. package/src/providers/spreadsheet/xlsx.ts +47 -16
  156. package/src/providers/storage/s3.ts +119 -47
  157. package/src/providers/support/zendesk.ts +196 -46
  158. package/src/providers/tasks/todoist.ts +20 -26
  159. package/src/providers/video-conferencing/google-meet.ts +17 -20
  160. package/src/providers/video-conferencing/jitsi.ts +14 -14
  161. package/src/providers/video-conferencing/teams.ts +14 -13
  162. package/src/providers/video-conferencing/zoom.ts +54 -49
  163. package/src/tools/data.ts +6 -16
  164. package/src/tools/index.ts +1 -0
  165. package/src/tools/system.ts +887 -0
  166. package/src/tools/web.ts +22 -10
  167. package/src/track-record.ts +106 -0
  168. package/src/types.ts +241 -13
  169. package/src/verb-registration.ts +197 -0
  170. package/src/worker.ts +370 -0
  171. package/src/wrap.ts +260 -0
  172. package/test/client.test.ts +146 -0
  173. package/test/communication-tools-extended.test.ts +734 -0
  174. package/test/data-tools-extended.test.ts +743 -0
  175. package/test/define-extended.test.ts +819 -0
  176. package/test/define.test.ts +150 -41
  177. package/test/entities.test.ts +623 -0
  178. package/test/extended-entities.test.ts +1228 -0
  179. package/test/provider-implementations.test.ts +725 -0
  180. package/test/provider-registry-extended.test.ts +583 -0
  181. package/test/providers/google-sheets.test.ts +851 -0
  182. package/test/providers/helpers.ts +554 -0
  183. package/test/providers/hubspot.test.ts +576 -0
  184. package/test/providers/slack.test.ts +932 -0
  185. package/test/providers/stripe.test.ts +701 -0
  186. package/test/providers.test.ts +578 -0
  187. package/test/system-tools-extended.test.ts +632 -0
  188. package/test/system.test.ts +673 -0
  189. package/test/tools.test.ts +15 -11
  190. package/test/types.test.ts +402 -0
  191. package/test/verb-registration.test.ts +395 -0
  192. package/test/web-tools.test.ts +553 -0
  193. package/test/worker-extended.test.ts +699 -0
  194. package/test/worker.test.ts +576 -0
  195. package/test/wrap.test.ts +366 -0
  196. package/tsconfig.json +3 -13
  197. package/vitest.config.ts +37 -0
  198. package/wrangler.jsonc +9 -0
  199. package/LICENSE +0 -21
  200. package/dist/providers/voice/vapi.d.ts +0 -27
  201. package/dist/providers/voice/vapi.d.ts.map +0 -1
  202. package/dist/providers/voice/vapi.js +0 -440
  203. package/dist/providers/voice/vapi.js.map +0 -1
  204. package/src/define.js +0 -259
  205. package/src/entities/advertising.js +0 -999
  206. package/src/entities/ai.js +0 -756
  207. package/src/entities/analytics.js +0 -1588
  208. package/src/entities/automation.js +0 -601
  209. package/src/entities/communication.js +0 -1150
  210. package/src/entities/crm.js +0 -1386
  211. package/src/entities/design.js +0 -546
  212. package/src/entities/development.js +0 -2212
  213. package/src/entities/document.js +0 -874
  214. package/src/entities/ecommerce.js +0 -1429
  215. package/src/entities/experiment.js +0 -1039
  216. package/src/entities/finance.js +0 -3478
  217. package/src/entities/forms.js +0 -1892
  218. package/src/entities/hr.js +0 -661
  219. package/src/entities/identity.js +0 -997
  220. package/src/entities/index.js +0 -282
  221. package/src/entities/infrastructure.js +0 -1153
  222. package/src/entities/knowledge.js +0 -1438
  223. package/src/entities/marketing.js +0 -1610
  224. package/src/entities/media.js +0 -1634
  225. package/src/entities/notification.js +0 -1199
  226. package/src/entities/presentation.js +0 -1274
  227. package/src/entities/productivity.js +0 -1317
  228. package/src/entities/project-management.js +0 -1136
  229. package/src/entities/recruiting.js +0 -736
  230. package/src/entities/shipping.js +0 -509
  231. package/src/entities/signature.js +0 -1102
  232. package/src/entities/site.js +0 -222
  233. package/src/entities/spreadsheet.js +0 -1341
  234. package/src/entities/storage.js +0 -1198
  235. package/src/entities/support.js +0 -1166
  236. package/src/entities/video-conferencing.js +0 -1750
  237. package/src/entities/video.js +0 -950
  238. package/src/entities.js +0 -1663
  239. package/src/index.js +0 -74
  240. package/src/providers/analytics/index.js +0 -17
  241. package/src/providers/analytics/mixpanel.js +0 -255
  242. package/src/providers/calendar/cal-com.js +0 -303
  243. package/src/providers/calendar/google-calendar.js +0 -335
  244. package/src/providers/calendar/index.js +0 -20
  245. package/src/providers/crm/hubspot.js +0 -566
  246. package/src/providers/crm/index.js +0 -17
  247. package/src/providers/development/github.js +0 -472
  248. package/src/providers/development/index.js +0 -17
  249. package/src/providers/ecommerce/index.js +0 -17
  250. package/src/providers/ecommerce/shopify.js +0 -378
  251. package/src/providers/email/index.js +0 -20
  252. package/src/providers/email/resend.js +0 -258
  253. package/src/providers/email/sendgrid.js +0 -161
  254. package/src/providers/finance/index.js +0 -17
  255. package/src/providers/finance/stripe.js +0 -549
  256. package/src/providers/forms/index.js +0 -17
  257. package/src/providers/forms/typeform.js +0 -500
  258. package/src/providers/index.js +0 -123
  259. package/src/providers/knowledge/index.js +0 -17
  260. package/src/providers/knowledge/notion.js +0 -389
  261. package/src/providers/marketing/index.js +0 -17
  262. package/src/providers/marketing/mailchimp.js +0 -443
  263. package/src/providers/media/cloudinary.js +0 -318
  264. package/src/providers/media/index.js +0 -17
  265. package/src/providers/messaging/index.js +0 -20
  266. package/src/providers/messaging/slack.js +0 -393
  267. package/src/providers/messaging/twilio-sms.js +0 -249
  268. package/src/providers/project-management/index.js +0 -17
  269. package/src/providers/project-management/linear.js +0 -575
  270. package/src/providers/registry.js +0 -86
  271. package/src/providers/spreadsheet/google-sheets.js +0 -375
  272. package/src/providers/spreadsheet/index.js +0 -20
  273. package/src/providers/spreadsheet/xlsx.js +0 -423
  274. package/src/providers/storage/index.js +0 -24
  275. package/src/providers/storage/s3.js +0 -419
  276. package/src/providers/support/index.js +0 -17
  277. package/src/providers/support/zendesk.js +0 -373
  278. package/src/providers/tasks/index.js +0 -17
  279. package/src/providers/tasks/todoist.js +0 -286
  280. package/src/providers/types.js +0 -9
  281. package/src/providers/video-conferencing/google-meet.js +0 -286
  282. package/src/providers/video-conferencing/index.js +0 -31
  283. package/src/providers/video-conferencing/jitsi.js +0 -254
  284. package/src/providers/video-conferencing/teams.js +0 -270
  285. package/src/providers/video-conferencing/zoom.js +0 -332
  286. package/src/registry.js +0 -128
  287. package/src/tools/communication.js +0 -184
  288. package/src/tools/data.js +0 -205
  289. package/src/tools/index.js +0 -11
  290. package/src/tools/web.js +0 -137
  291. package/src/types.js +0 -10
  292. package/test/define.test.js +0 -306
  293. package/test/registry.test.js +0 -357
  294. package/test/tools.test.js +0 -363
@@ -69,7 +69,7 @@ class AwsSignatureV4 {
69
69
  private getCanonicalQueryString(params: Record<string, string>): string {
70
70
  return Object.keys(params)
71
71
  .sort()
72
- .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
72
+ .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(params[key] ?? '')}`)
73
73
  .join('&')
74
74
  }
75
75
 
@@ -103,7 +103,7 @@ class AwsSignatureV4 {
103
103
  // Create canonical request
104
104
  const canonicalHeaders = Object.keys(signedHeaders)
105
105
  .sort()
106
- .map((key) => `${key.toLowerCase()}:${signedHeaders[key].trim()}`)
106
+ .map((key) => `${key.toLowerCase()}:${signedHeaders[key]!.trim()}`)
107
107
  .join('\n')
108
108
 
109
109
  const signedHeadersList = Object.keys(signedHeaders)
@@ -163,11 +163,11 @@ export function createS3Provider(config: ProviderConfig): StorageProvider {
163
163
  info: s3Info,
164
164
 
165
165
  async initialize(cfg: ProviderConfig): Promise<void> {
166
- accessKeyId = cfg.accessKeyId as string
167
- secretAccessKey = cfg.secretAccessKey as string
168
- bucket = cfg.bucket as string
169
- region = cfg.region as string
170
- endpoint = (cfg.endpoint as string) || `https://${bucket}.s3.${region}.amazonaws.com`
166
+ accessKeyId = cfg['accessKeyId'] as string
167
+ secretAccessKey = cfg['secretAccessKey'] as string
168
+ bucket = cfg['bucket'] as string
169
+ region = cfg['region'] as string
170
+ endpoint = (cfg['endpoint'] as string) || `https://${bucket}.s3.${region}.amazonaws.com`
171
171
 
172
172
  if (!accessKeyId || !secretAccessKey || !bucket || !region) {
173
173
  throw new Error('S3 requires accessKeyId, secretAccessKey, bucket, and region')
@@ -179,7 +179,12 @@ export function createS3Provider(config: ProviderConfig): StorageProvider {
179
179
  async healthCheck(): Promise<ProviderHealth> {
180
180
  const start = Date.now()
181
181
  try {
182
- const headers = await signer.sign('HEAD', '/', { host: `${bucket}.s3.${region}.amazonaws.com` }, null)
182
+ const headers = await signer.sign(
183
+ 'HEAD',
184
+ '/',
185
+ { host: `${bucket}.s3.${region}.amazonaws.com` },
186
+ null
187
+ )
183
188
 
184
189
  const response = await fetch(`${endpoint}/`, {
185
190
  method: 'HEAD',
@@ -206,7 +211,11 @@ export function createS3Provider(config: ProviderConfig): StorageProvider {
206
211
  // No cleanup needed
207
212
  },
208
213
 
209
- async upload(path: string, content: Buffer | string, options?: StorageUploadOptions): Promise<StorageFileData> {
214
+ async upload(
215
+ path: string,
216
+ content: Buffer | string,
217
+ options?: StorageUploadOptions
218
+ ): Promise<StorageFileData> {
210
219
  try {
211
220
  const buffer = typeof content === 'string' ? Buffer.from(content) : content
212
221
  const headers: Record<string, string> = {
@@ -244,20 +253,27 @@ export function createS3Provider(config: ProviderConfig): StorageProvider {
244
253
  path,
245
254
  name: path.split('/').pop() || path,
246
255
  size: buffer.length,
247
- contentType: options?.contentType,
248
- etag,
256
+ ...(options?.contentType !== undefined && { contentType: options.contentType }),
257
+ ...(etag !== undefined && { etag }),
249
258
  lastModified: new Date(),
250
259
  isFolder: false,
251
260
  url: `${endpoint}/${path}`,
252
261
  }
253
262
  } catch (error) {
254
- throw new Error(`Failed to upload to S3: ${error instanceof Error ? error.message : 'Unknown error'}`)
263
+ throw new Error(
264
+ `Failed to upload to S3: ${error instanceof Error ? error.message : 'Unknown error'}`
265
+ )
255
266
  }
256
267
  },
257
268
 
258
269
  async download(path: string): Promise<Buffer> {
259
270
  try {
260
- const headers = await signer.sign('GET', `/${path}`, { host: `${bucket}.s3.${region}.amazonaws.com` }, null)
271
+ const headers = await signer.sign(
272
+ 'GET',
273
+ `/${path}`,
274
+ { host: `${bucket}.s3.${region}.amazonaws.com` },
275
+ null
276
+ )
261
277
 
262
278
  const response = await fetch(`${endpoint}/${path}`, {
263
279
  method: 'GET',
@@ -271,13 +287,20 @@ export function createS3Provider(config: ProviderConfig): StorageProvider {
271
287
  const arrayBuffer = await response.arrayBuffer()
272
288
  return Buffer.from(arrayBuffer)
273
289
  } catch (error) {
274
- throw new Error(`Failed to download from S3: ${error instanceof Error ? error.message : 'Unknown error'}`)
290
+ throw new Error(
291
+ `Failed to download from S3: ${error instanceof Error ? error.message : 'Unknown error'}`
292
+ )
275
293
  }
276
294
  },
277
295
 
278
296
  async delete(path: string): Promise<boolean> {
279
297
  try {
280
- const headers = await signer.sign('DELETE', `/${path}`, { host: `${bucket}.s3.${region}.amazonaws.com` }, null)
298
+ const headers = await signer.sign(
299
+ 'DELETE',
300
+ `/${path}`,
301
+ { host: `${bucket}.s3.${region}.amazonaws.com` },
302
+ null
303
+ )
281
304
 
282
305
  const response = await fetch(`${endpoint}/${path}`, {
283
306
  method: 'DELETE',
@@ -286,22 +309,27 @@ export function createS3Provider(config: ProviderConfig): StorageProvider {
286
309
 
287
310
  return response.ok || response.status === 204
288
311
  } catch (error) {
289
- throw new Error(`Failed to delete from S3: ${error instanceof Error ? error.message : 'Unknown error'}`)
312
+ throw new Error(
313
+ `Failed to delete from S3: ${error instanceof Error ? error.message : 'Unknown error'}`
314
+ )
290
315
  }
291
316
  },
292
317
 
293
- async list(prefix: string = '', options?: StorageListOptions): Promise<PaginatedResult<StorageFileData>> {
318
+ async list(
319
+ prefix: string = '',
320
+ options?: StorageListOptions
321
+ ): Promise<PaginatedResult<StorageFileData>> {
294
322
  try {
295
323
  const queryParams: Record<string, string> = {
296
324
  'list-type': '2',
297
325
  }
298
326
 
299
327
  if (prefix) {
300
- queryParams.prefix = prefix
328
+ queryParams['prefix'] = prefix
301
329
  }
302
330
 
303
331
  if (options?.delimiter) {
304
- queryParams.delimiter = options.delimiter
332
+ queryParams['delimiter'] = options.delimiter
305
333
  }
306
334
 
307
335
  if (options?.limit) {
@@ -312,10 +340,16 @@ export function createS3Provider(config: ProviderConfig): StorageProvider {
312
340
  queryParams['continuation-token'] = options.cursor
313
341
  }
314
342
 
315
- const headers = await signer.sign('GET', '/', { host: `${bucket}.s3.${region}.amazonaws.com` }, null, queryParams)
343
+ const headers = await signer.sign(
344
+ 'GET',
345
+ '/',
346
+ { host: `${bucket}.s3.${region}.amazonaws.com` },
347
+ null,
348
+ queryParams
349
+ )
316
350
 
317
351
  const queryString = Object.keys(queryParams)
318
- .map((key) => `${key}=${encodeURIComponent(queryParams[key])}`)
352
+ .map((key) => `${key}=${encodeURIComponent(queryParams[key] ?? '')}`)
319
353
  .join('&')
320
354
 
321
355
  const response = await fetch(`${endpoint}/?${queryString}`, {
@@ -334,29 +368,33 @@ export function createS3Provider(config: ProviderConfig): StorageProvider {
334
368
  const contentsMatches = xmlText.matchAll(/<Contents>(.*?)<\/Contents>/gs)
335
369
  for (const match of contentsMatches) {
336
370
  const content = match[1]
371
+ if (!content) continue
337
372
  const keyMatch = content.match(/<Key>(.*?)<\/Key>/)
338
373
  const sizeMatch = content.match(/<Size>(.*?)<\/Size>/)
339
374
  const lastModifiedMatch = content.match(/<LastModified>(.*?)<\/LastModified>/)
340
375
  const etagMatch = content.match(/<ETag>(.*?)<\/ETag>/)
341
376
 
342
- if (keyMatch) {
343
- const path = keyMatch[1]
377
+ const pathValue = keyMatch?.[1]
378
+ if (pathValue) {
344
379
  items.push({
345
- path,
346
- name: path.split('/').pop() || path,
347
- size: sizeMatch ? parseInt(sizeMatch[1], 10) : 0,
348
- etag: etagMatch ? etagMatch[1].replace(/"/g, '') : undefined,
349
- lastModified: lastModifiedMatch ? new Date(lastModifiedMatch[1]) : new Date(),
380
+ path: pathValue,
381
+ name: pathValue.split('/').pop() || pathValue,
382
+ size: sizeMatch?.[1] ? parseInt(sizeMatch[1], 10) : 0,
383
+ ...(etagMatch?.[1] && { etag: etagMatch[1].replace(/"/g, '') }),
384
+ lastModified: lastModifiedMatch?.[1] ? new Date(lastModifiedMatch[1]) : new Date(),
350
385
  isFolder: false,
351
- url: `${endpoint}/${path}`,
386
+ url: `${endpoint}/${pathValue}`,
352
387
  })
353
388
  }
354
389
  }
355
390
 
356
391
  // Parse common prefixes (folders)
357
- const prefixMatches = xmlText.matchAll(/<CommonPrefixes>.*?<Prefix>(.*?)<\/Prefix>.*?<\/CommonPrefixes>/gs)
392
+ const prefixMatches = xmlText.matchAll(
393
+ /<CommonPrefixes>.*?<Prefix>(.*?)<\/Prefix>.*?<\/CommonPrefixes>/gs
394
+ )
358
395
  for (const match of prefixMatches) {
359
396
  const folderPath = match[1]
397
+ if (!folderPath) continue
360
398
  items.push({
361
399
  path: folderPath,
362
400
  name: folderPath.split('/').filter(Boolean).pop() || folderPath,
@@ -367,21 +405,30 @@ export function createS3Provider(config: ProviderConfig): StorageProvider {
367
405
  }
368
406
 
369
407
  const isTruncated = xmlText.includes('<IsTruncated>true</IsTruncated>')
370
- const nextTokenMatch = xmlText.match(/<NextContinuationToken>(.*?)<\/NextContinuationToken>/)
408
+ const nextTokenMatch = xmlText.match(
409
+ /<NextContinuationToken>(.*?)<\/NextContinuationToken>/
410
+ )
371
411
 
372
412
  return {
373
413
  items,
374
414
  hasMore: isTruncated,
375
- nextCursor: nextTokenMatch ? nextTokenMatch[1] : undefined,
415
+ ...(nextTokenMatch?.[1] !== undefined && { nextCursor: nextTokenMatch[1] }),
376
416
  }
377
417
  } catch (error) {
378
- throw new Error(`Failed to list S3 objects: ${error instanceof Error ? error.message : 'Unknown error'}`)
418
+ throw new Error(
419
+ `Failed to list S3 objects: ${error instanceof Error ? error.message : 'Unknown error'}`
420
+ )
379
421
  }
380
422
  },
381
423
 
382
424
  async getMetadata(path: string): Promise<StorageFileData | null> {
383
425
  try {
384
- const headers = await signer.sign('HEAD', `/${path}`, { host: `${bucket}.s3.${region}.amazonaws.com` }, null)
426
+ const headers = await signer.sign(
427
+ 'HEAD',
428
+ `/${path}`,
429
+ { host: `${bucket}.s3.${region}.amazonaws.com` },
430
+ null
431
+ )
385
432
 
386
433
  const response = await fetch(`${endpoint}/${path}`, {
387
434
  method: 'HEAD',
@@ -404,14 +451,16 @@ export function createS3Provider(config: ProviderConfig): StorageProvider {
404
451
  path,
405
452
  name: path.split('/').pop() || path,
406
453
  size: contentLength ? parseInt(contentLength, 10) : 0,
407
- contentType: contentType || undefined,
408
- etag,
454
+ ...(contentType && { contentType }),
455
+ ...(etag && { etag }),
409
456
  lastModified: lastModified ? new Date(lastModified) : new Date(),
410
457
  isFolder: false,
411
458
  url: `${endpoint}/${path}`,
412
459
  }
413
460
  } catch (error) {
414
- throw new Error(`Failed to get S3 metadata: ${error instanceof Error ? error.message : 'Unknown error'}`)
461
+ throw new Error(
462
+ `Failed to get S3 metadata: ${error instanceof Error ? error.message : 'Unknown error'}`
463
+ )
415
464
  }
416
465
  },
417
466
 
@@ -444,7 +493,9 @@ export function createS3Provider(config: ProviderConfig): StorageProvider {
444
493
 
445
494
  return metadata
446
495
  } catch (error) {
447
- throw new Error(`Failed to copy in S3: ${error instanceof Error ? error.message : 'Unknown error'}`)
496
+ throw new Error(
497
+ `Failed to copy in S3: ${error instanceof Error ? error.message : 'Unknown error'}`
498
+ )
448
499
  }
449
500
  },
450
501
 
@@ -458,7 +509,9 @@ export function createS3Provider(config: ProviderConfig): StorageProvider {
458
509
 
459
510
  return metadata
460
511
  } catch (error) {
461
- throw new Error(`Failed to move in S3: ${error instanceof Error ? error.message : 'Unknown error'}`)
512
+ throw new Error(
513
+ `Failed to move in S3: ${error instanceof Error ? error.message : 'Unknown error'}`
514
+ )
462
515
  }
463
516
  },
464
517
 
@@ -469,28 +522,43 @@ export function createS3Provider(config: ProviderConfig): StorageProvider {
469
522
 
470
523
  const queryParams: Record<string, string> = {
471
524
  'X-Amz-Algorithm': 'AWS4-HMAC-SHA256',
472
- 'X-Amz-Credential': `${accessKeyId}/${new Date().toISOString().slice(0, 10).replace(/-/g, '')}/${region}/s3/aws4_request`,
525
+ 'X-Amz-Credential': `${accessKeyId}/${new Date()
526
+ .toISOString()
527
+ .slice(0, 10)
528
+ .replace(/-/g, '')}/${region}/s3/aws4_request`,
473
529
  'X-Amz-Date': new Date().toISOString().replace(/[:-]|\.\d{3}/g, ''),
474
530
  'X-Amz-Expires': expiresIn.toString(),
475
531
  'X-Amz-SignedHeaders': 'host',
476
532
  }
477
533
 
478
- const headers = await signer.sign('GET', `/${path}`, { host: `${bucket}.s3.${region}.amazonaws.com` }, null, queryParams)
534
+ const headers = await signer.sign(
535
+ 'GET',
536
+ `/${path}`,
537
+ { host: `${bucket}.s3.${region}.amazonaws.com` },
538
+ null,
539
+ queryParams
540
+ )
479
541
 
480
542
  // Extract signature from Authorization header
481
543
  const authHeader = headers['Authorization']
482
- const signatureMatch = authHeader.match(/Signature=([a-f0-9]+)/)
483
- if (signatureMatch) {
484
- queryParams['X-Amz-Signature'] = signatureMatch[1]
544
+ if (authHeader) {
545
+ const signatureMatch = authHeader.match(/Signature=([a-f0-9]+)/)
546
+ if (signatureMatch?.[1]) {
547
+ queryParams['X-Amz-Signature'] = signatureMatch[1]
548
+ }
485
549
  }
486
550
 
487
551
  const queryString = Object.keys(queryParams)
488
- .map((key) => `${key}=${encodeURIComponent(queryParams[key])}`)
552
+ .map((key) => `${key}=${encodeURIComponent(queryParams[key] ?? '')}`)
489
553
  .join('&')
490
554
 
491
555
  return `${endpoint}/${path}?${queryString}`
492
556
  } catch (error) {
493
- throw new Error(`Failed to generate signed URL: ${error instanceof Error ? error.message : 'Unknown error'}`)
557
+ throw new Error(
558
+ `Failed to generate signed URL: ${
559
+ error instanceof Error ? error.message : 'Unknown error'
560
+ }`
561
+ )
494
562
  }
495
563
  },
496
564
 
@@ -501,7 +569,11 @@ export function createS3Provider(config: ProviderConfig): StorageProvider {
501
569
  await this.upload(folderPath, Buffer.from(''), { contentType: 'application/x-directory' })
502
570
  return true
503
571
  } catch (error) {
504
- throw new Error(`Failed to create folder in S3: ${error instanceof Error ? error.message : 'Unknown error'}`)
572
+ throw new Error(
573
+ `Failed to create folder in S3: ${
574
+ error instanceof Error ? error.message : 'Unknown error'
575
+ }`
576
+ )
505
577
  }
506
578
  },
507
579
  }