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
@@ -0,0 +1,578 @@
1
+ /**
2
+ * Tests for Provider Registry and Provider Definitions
3
+ *
4
+ * Covers provider registration, discovery, and instantiation.
5
+ */
6
+
7
+ import { describe, it, expect, beforeEach } from 'vitest'
8
+ import {
9
+ // Provider registry
10
+ providerRegistry,
11
+ createProviderRegistry,
12
+ registerProvider,
13
+ getProvider,
14
+ listProviders,
15
+ defineProvider,
16
+
17
+ // Provider info exports
18
+ sendgridInfo,
19
+ resendInfo,
20
+ slackInfo,
21
+ twilioSmsInfo,
22
+ xlsxInfo,
23
+ googleSheetsInfo,
24
+ cloudinaryInfo,
25
+ todoistInfo,
26
+ stripeInfo,
27
+ zendeskInfo,
28
+ linearInfo,
29
+ notionInfo,
30
+ hubspotInfo,
31
+ shopifyInfo,
32
+ githubInfo,
33
+ typeformInfo,
34
+ mixpanelInfo,
35
+ zoomInfo,
36
+ googleMeetInfo,
37
+ teamsInfo,
38
+ jitsiInfo,
39
+ googleCalendarInfo,
40
+ s3Info,
41
+
42
+ // Registration helpers
43
+ registerAllProviders,
44
+ registerEmailProviders,
45
+ registerMessagingProviders,
46
+ registerSpreadsheetProviders,
47
+
48
+ // Provider collections
49
+ allProviders,
50
+ } from '../src/providers/index.js'
51
+
52
+ import type {
53
+ BaseProvider,
54
+ ProviderCategory,
55
+ ProviderConfig,
56
+ ProviderInfo,
57
+ ProviderHealth,
58
+ EmailProvider,
59
+ MessagingProvider,
60
+ SpreadsheetProvider,
61
+ } from '../src/providers/types.js'
62
+
63
+ describe('Provider Registry', () => {
64
+ describe('createProviderRegistry', () => {
65
+ it('creates an isolated registry', () => {
66
+ const registry = createProviderRegistry()
67
+
68
+ expect(registry.list()).toHaveLength(0)
69
+ })
70
+
71
+ it('registries are independent', () => {
72
+ const registry1 = createProviderRegistry()
73
+ const registry2 = createProviderRegistry()
74
+
75
+ const mockInfo: ProviderInfo = {
76
+ id: 'test.provider',
77
+ name: 'Test Provider',
78
+ description: 'Test',
79
+ category: 'email',
80
+ requiredConfig: [],
81
+ }
82
+
83
+ registry1.register(mockInfo, async () => createMockProvider(mockInfo))
84
+
85
+ expect(registry1.has('test.provider')).toBe(true)
86
+ expect(registry2.has('test.provider')).toBe(false)
87
+ })
88
+ })
89
+
90
+ describe('register', () => {
91
+ it('registers a provider', () => {
92
+ const registry = createProviderRegistry()
93
+
94
+ const mockInfo: ProviderInfo = {
95
+ id: 'mock.email',
96
+ name: 'Mock Email',
97
+ description: 'A mock email provider',
98
+ category: 'email',
99
+ requiredConfig: ['apiKey'],
100
+ }
101
+
102
+ registry.register(mockInfo, async (config) => createMockProvider(mockInfo))
103
+
104
+ expect(registry.has('mock.email')).toBe(true)
105
+ })
106
+
107
+ it('throws on duplicate registration', () => {
108
+ const registry = createProviderRegistry()
109
+
110
+ const mockInfo: ProviderInfo = {
111
+ id: 'duplicate.provider',
112
+ name: 'Duplicate',
113
+ description: 'Test',
114
+ category: 'email',
115
+ requiredConfig: [],
116
+ }
117
+
118
+ registry.register(mockInfo, async () => createMockProvider(mockInfo))
119
+
120
+ expect(() => {
121
+ registry.register(mockInfo, async () => createMockProvider(mockInfo))
122
+ }).toThrow("Provider 'duplicate.provider' is already registered")
123
+ })
124
+ })
125
+
126
+ describe('get', () => {
127
+ it('returns registered provider', () => {
128
+ const registry = createProviderRegistry()
129
+
130
+ const mockInfo: ProviderInfo = {
131
+ id: 'get.test',
132
+ name: 'Get Test',
133
+ description: 'Test',
134
+ category: 'messaging',
135
+ requiredConfig: [],
136
+ }
137
+
138
+ registry.register(mockInfo, async () => createMockProvider(mockInfo))
139
+
140
+ const result = registry.get('get.test')
141
+
142
+ expect(result).toBeDefined()
143
+ expect(result?.info.id).toBe('get.test')
144
+ expect(result?.info.category).toBe('messaging')
145
+ })
146
+
147
+ it('returns undefined for non-existent provider', () => {
148
+ const registry = createProviderRegistry()
149
+
150
+ expect(registry.get('non.existent')).toBeUndefined()
151
+ })
152
+ })
153
+
154
+ describe('list', () => {
155
+ it('returns all providers', () => {
156
+ const registry = createProviderRegistry()
157
+
158
+ registry.register(
159
+ { id: 'list.a', name: 'A', description: 'A', category: 'email', requiredConfig: [] },
160
+ async (config) => createMockProvider({ id: 'list.a', name: 'A', description: 'A', category: 'email', requiredConfig: [] })
161
+ )
162
+ registry.register(
163
+ { id: 'list.b', name: 'B', description: 'B', category: 'messaging', requiredConfig: [] },
164
+ async (config) => createMockProvider({ id: 'list.b', name: 'B', description: 'B', category: 'messaging', requiredConfig: [] })
165
+ )
166
+
167
+ const all = registry.list()
168
+
169
+ expect(all).toHaveLength(2)
170
+ })
171
+
172
+ it('filters by category', () => {
173
+ const registry = createProviderRegistry()
174
+
175
+ registry.register(
176
+ { id: 'cat.email', name: 'Email', description: 'Email', category: 'email', requiredConfig: [] },
177
+ async () => createMockProvider({ id: 'cat.email', name: 'Email', description: 'Email', category: 'email', requiredConfig: [] })
178
+ )
179
+ registry.register(
180
+ { id: 'cat.sms', name: 'SMS', description: 'SMS', category: 'messaging', requiredConfig: [] },
181
+ async () => createMockProvider({ id: 'cat.sms', name: 'SMS', description: 'SMS', category: 'messaging', requiredConfig: [] })
182
+ )
183
+ registry.register(
184
+ { id: 'cat.email2', name: 'Email2', description: 'Email2', category: 'email', requiredConfig: [] },
185
+ async () => createMockProvider({ id: 'cat.email2', name: 'Email2', description: 'Email2', category: 'email', requiredConfig: [] })
186
+ )
187
+
188
+ const emailProviders = registry.list('email')
189
+
190
+ expect(emailProviders).toHaveLength(2)
191
+ expect(emailProviders.every((p) => p.info.category === 'email')).toBe(true)
192
+ })
193
+ })
194
+
195
+ describe('create', () => {
196
+ it('creates provider instance', async () => {
197
+ const registry = createProviderRegistry()
198
+
199
+ const mockInfo: ProviderInfo = {
200
+ id: 'create.test',
201
+ name: 'Create Test',
202
+ description: 'Test',
203
+ category: 'email',
204
+ requiredConfig: [],
205
+ }
206
+
207
+ registry.register(mockInfo, async (config) => createMockProvider(mockInfo))
208
+
209
+ const provider = await registry.create('create.test', {})
210
+
211
+ expect(provider.info.id).toBe('create.test')
212
+ })
213
+
214
+ it('throws for non-existent provider', async () => {
215
+ const registry = createProviderRegistry()
216
+
217
+ await expect(registry.create('non.existent', {})).rejects.toThrow(
218
+ "Provider 'non.existent' not found"
219
+ )
220
+ })
221
+
222
+ it('validates required config', async () => {
223
+ const registry = createProviderRegistry()
224
+
225
+ const mockInfo: ProviderInfo = {
226
+ id: 'config.test',
227
+ name: 'Config Test',
228
+ description: 'Test',
229
+ category: 'email',
230
+ requiredConfig: ['apiKey', 'apiSecret'],
231
+ }
232
+
233
+ registry.register(mockInfo, async (config) => createMockProvider(mockInfo))
234
+
235
+ await expect(registry.create('config.test', { apiKey: 'key' })).rejects.toThrow(
236
+ "missing required config: apiSecret"
237
+ )
238
+ })
239
+
240
+ it('passes config to factory', async () => {
241
+ const registry = createProviderRegistry()
242
+ let receivedConfig: ProviderConfig | undefined
243
+
244
+ const mockInfo: ProviderInfo = {
245
+ id: 'factory.test',
246
+ name: 'Factory Test',
247
+ description: 'Test',
248
+ category: 'email',
249
+ requiredConfig: ['apiKey'],
250
+ }
251
+
252
+ registry.register(mockInfo, async (config) => {
253
+ receivedConfig = config
254
+ return createMockProvider(mockInfo)
255
+ })
256
+
257
+ await registry.create('factory.test', { apiKey: 'test-key' })
258
+
259
+ expect(receivedConfig?.apiKey).toBe('test-key')
260
+ })
261
+ })
262
+
263
+ describe('has', () => {
264
+ it('returns true for registered provider', () => {
265
+ const registry = createProviderRegistry()
266
+
267
+ registry.register(
268
+ { id: 'has.test', name: 'Has', description: 'Has', category: 'email', requiredConfig: [] },
269
+ async () => createMockProvider({ id: 'has.test', name: 'Has', description: 'Has', category: 'email', requiredConfig: [] })
270
+ )
271
+
272
+ expect(registry.has('has.test')).toBe(true)
273
+ })
274
+
275
+ it('returns false for non-existent provider', () => {
276
+ const registry = createProviderRegistry()
277
+
278
+ expect(registry.has('non.existent')).toBe(false)
279
+ })
280
+ })
281
+ })
282
+
283
+ describe('defineProvider', () => {
284
+ it('creates provider definition', () => {
285
+ const mockInfo: ProviderInfo = {
286
+ id: 'define.test',
287
+ name: 'Define Test',
288
+ description: 'Test',
289
+ category: 'email',
290
+ requiredConfig: [],
291
+ }
292
+
293
+ const definition = defineProvider(mockInfo, async () => createMockProvider(mockInfo))
294
+
295
+ expect(definition.info).toBe(mockInfo)
296
+ expect(typeof definition.factory).toBe('function')
297
+ expect(typeof definition.register).toBe('function')
298
+ })
299
+ })
300
+
301
+ describe('Provider Info Exports', () => {
302
+ describe('Email Providers', () => {
303
+ it('sendgrid info is valid', () => {
304
+ expect(sendgridInfo.id).toBe('email.sendgrid')
305
+ expect(sendgridInfo.name).toBe('SendGrid')
306
+ expect(sendgridInfo.category).toBe('email')
307
+ expect(sendgridInfo.requiredConfig).toContain('apiKey')
308
+ })
309
+
310
+ it('resend info is valid', () => {
311
+ expect(resendInfo.id).toBe('email.resend')
312
+ expect(resendInfo.name).toBe('Resend')
313
+ expect(resendInfo.category).toBe('email')
314
+ expect(resendInfo.requiredConfig).toContain('apiKey')
315
+ })
316
+ })
317
+
318
+ describe('Messaging Providers', () => {
319
+ it('slack info is valid', () => {
320
+ expect(slackInfo.id).toBe('messaging.slack')
321
+ expect(slackInfo.name).toBe('Slack')
322
+ expect(slackInfo.category).toBe('messaging')
323
+ expect(slackInfo.requiredConfig).toContain('accessToken')
324
+ })
325
+
326
+ it('twilio sms info is valid', () => {
327
+ expect(twilioSmsInfo.id).toBe('messaging.twilio-sms')
328
+ expect(twilioSmsInfo.name).toBe('Twilio SMS')
329
+ expect(twilioSmsInfo.category).toBe('messaging')
330
+ expect(twilioSmsInfo.requiredConfig).toContain('accountSid')
331
+ expect(twilioSmsInfo.requiredConfig).toContain('authToken')
332
+ })
333
+ })
334
+
335
+ describe('Spreadsheet Providers', () => {
336
+ it('xlsx info is valid', () => {
337
+ expect(xlsxInfo.id).toBe('spreadsheet.xlsx')
338
+ expect(xlsxInfo.name).toBe('XLSX (SheetJS)')
339
+ expect(xlsxInfo.category).toBe('spreadsheet')
340
+ expect(xlsxInfo.requiredConfig).toHaveLength(0) // No required config for local xlsx
341
+ })
342
+
343
+ it('google sheets info is valid', () => {
344
+ expect(googleSheetsInfo.id).toBe('spreadsheet.google-sheets')
345
+ expect(googleSheetsInfo.name).toBe('Google Sheets')
346
+ expect(googleSheetsInfo.category).toBe('spreadsheet')
347
+ })
348
+ })
349
+
350
+ describe('Media Providers', () => {
351
+ it('cloudinary info is valid', () => {
352
+ expect(cloudinaryInfo.id).toBe('media.cloudinary')
353
+ expect(cloudinaryInfo.name).toBe('Cloudinary')
354
+ expect(cloudinaryInfo.category).toBe('media')
355
+ expect(cloudinaryInfo.requiredConfig).toContain('cloudName')
356
+ expect(cloudinaryInfo.requiredConfig).toContain('apiKey')
357
+ expect(cloudinaryInfo.requiredConfig).toContain('apiSecret')
358
+ })
359
+ })
360
+
361
+ describe('Task Providers', () => {
362
+ it('todoist info is valid', () => {
363
+ expect(todoistInfo.id).toBe('tasks.todoist')
364
+ expect(todoistInfo.name).toBe('Todoist')
365
+ expect(todoistInfo.category).toBe('tasks')
366
+ expect(todoistInfo.requiredConfig).toContain('apiKey')
367
+ })
368
+ })
369
+
370
+ describe('Finance Providers', () => {
371
+ it('stripe info is valid', () => {
372
+ expect(stripeInfo.id).toBe('finance.stripe')
373
+ expect(stripeInfo.name).toBe('Stripe')
374
+ expect(stripeInfo.category).toBe('finance')
375
+ expect(stripeInfo.requiredConfig).toContain('apiKey')
376
+ })
377
+ })
378
+
379
+ describe('Support Providers', () => {
380
+ it('zendesk info is valid', () => {
381
+ expect(zendeskInfo.id).toBe('support.zendesk')
382
+ expect(zendeskInfo.name).toBe('Zendesk')
383
+ expect(zendeskInfo.category).toBe('support')
384
+ expect(zendeskInfo.requiredConfig).toContain('subdomain')
385
+ })
386
+ })
387
+
388
+ describe('Project Management Providers', () => {
389
+ it('linear info is valid', () => {
390
+ expect(linearInfo.id).toBe('project-management.linear')
391
+ expect(linearInfo.name).toBe('Linear')
392
+ expect(linearInfo.category).toBe('project-management')
393
+ expect(linearInfo.requiredConfig).toContain('apiKey')
394
+ })
395
+ })
396
+
397
+ describe('Knowledge Providers', () => {
398
+ it('notion info is valid', () => {
399
+ expect(notionInfo.id).toBe('knowledge.notion')
400
+ expect(notionInfo.name).toBe('Notion')
401
+ expect(notionInfo.category).toBe('knowledge')
402
+ expect(notionInfo.requiredConfig).toContain('integrationToken')
403
+ })
404
+ })
405
+
406
+ describe('CRM Providers', () => {
407
+ it('hubspot info is valid', () => {
408
+ expect(hubspotInfo.id).toBe('crm.hubspot')
409
+ expect(hubspotInfo.name).toBe('HubSpot')
410
+ expect(hubspotInfo.category).toBe('crm')
411
+ expect(hubspotInfo.requiredConfig).toContain('accessToken')
412
+ })
413
+ })
414
+
415
+ describe('E-commerce Providers', () => {
416
+ it('shopify info is valid', () => {
417
+ expect(shopifyInfo.id).toBe('ecommerce.shopify')
418
+ expect(shopifyInfo.name).toBe('Shopify')
419
+ expect(shopifyInfo.category).toBe('ecommerce')
420
+ expect(shopifyInfo.requiredConfig).toContain('shopDomain')
421
+ expect(shopifyInfo.requiredConfig).toContain('accessToken')
422
+ })
423
+ })
424
+
425
+ describe('Development Providers', () => {
426
+ it('github info is valid', () => {
427
+ expect(githubInfo.id).toBe('development.github')
428
+ expect(githubInfo.name).toBe('GitHub')
429
+ expect(githubInfo.category).toBe('development')
430
+ expect(githubInfo.requiredConfig).toContain('accessToken')
431
+ })
432
+ })
433
+
434
+ describe('Forms Providers', () => {
435
+ it('typeform info is valid', () => {
436
+ expect(typeformInfo.id).toBe('forms.typeform')
437
+ expect(typeformInfo.name).toBe('Typeform')
438
+ expect(typeformInfo.category).toBe('forms')
439
+ expect(typeformInfo.requiredConfig).toContain('accessToken')
440
+ })
441
+ })
442
+
443
+ describe('Analytics Providers', () => {
444
+ it('mixpanel info is valid', () => {
445
+ expect(mixpanelInfo.id).toBe('analytics.mixpanel')
446
+ expect(mixpanelInfo.name).toBe('Mixpanel')
447
+ expect(mixpanelInfo.category).toBe('analytics')
448
+ expect(mixpanelInfo.requiredConfig).toContain('projectToken')
449
+ })
450
+ })
451
+
452
+ describe('Video Conferencing Providers', () => {
453
+ it('zoom info is valid', () => {
454
+ expect(zoomInfo.id).toBe('video-conferencing.zoom')
455
+ expect(zoomInfo.name).toBe('Zoom')
456
+ expect(zoomInfo.category).toBe('video-conferencing')
457
+ })
458
+
459
+ it('google meet info is valid', () => {
460
+ expect(googleMeetInfo.id).toBe('meeting.google-meet')
461
+ expect(googleMeetInfo.name).toBe('Google Meet')
462
+ expect(googleMeetInfo.category).toBe('video-conferencing')
463
+ })
464
+
465
+ it('teams info is valid', () => {
466
+ expect(teamsInfo.id).toBe('meeting.teams')
467
+ expect(teamsInfo.name).toBe('Microsoft Teams')
468
+ expect(teamsInfo.category).toBe('video-conferencing')
469
+ })
470
+
471
+ it('jitsi info is valid', () => {
472
+ expect(jitsiInfo.id).toBe('meeting.jitsi')
473
+ expect(jitsiInfo.name).toBe('Jitsi Meet')
474
+ expect(jitsiInfo.category).toBe('video-conferencing')
475
+ })
476
+ })
477
+
478
+ describe('Calendar Providers', () => {
479
+ it('google calendar info is valid', () => {
480
+ expect(googleCalendarInfo.id).toBe('calendar.google-calendar')
481
+ expect(googleCalendarInfo.name).toBe('Google Calendar')
482
+ expect(googleCalendarInfo.category).toBe('calendar')
483
+ })
484
+ })
485
+
486
+ describe('Storage Providers', () => {
487
+ it('s3 info is valid', () => {
488
+ expect(s3Info.id).toBe('storage.s3')
489
+ expect(s3Info.name).toBe('AWS S3')
490
+ expect(s3Info.category).toBe('storage')
491
+ expect(s3Info.requiredConfig).toContain('accessKeyId')
492
+ expect(s3Info.requiredConfig).toContain('secretAccessKey')
493
+ expect(s3Info.requiredConfig).toContain('bucket')
494
+ expect(s3Info.requiredConfig).toContain('region')
495
+ })
496
+ })
497
+ })
498
+
499
+ describe('All Providers Collection', () => {
500
+ it('organizes providers by category', () => {
501
+ expect(allProviders.email).toContain('email.sendgrid')
502
+ expect(allProviders.email).toContain('email.resend')
503
+
504
+ expect(allProviders.messaging).toContain('messaging.slack')
505
+ expect(allProviders.messaging).toContain('messaging.twilio-sms')
506
+
507
+ expect(allProviders.spreadsheet).toContain('spreadsheet.xlsx')
508
+ expect(allProviders.spreadsheet).toContain('spreadsheet.google-sheets')
509
+
510
+ expect(allProviders.task).toContain('task.todoist')
511
+
512
+ expect(allProviders.project).toContain('project.linear')
513
+
514
+ expect(allProviders.code).toContain('code.github')
515
+
516
+ expect(allProviders.sales).toContain('sales.hubspot')
517
+
518
+ expect(allProviders.finance).toContain('finance.stripe')
519
+
520
+ expect(allProviders.support).toContain('support.zendesk')
521
+
522
+ expect(allProviders.commerce).toContain('commerce.shopify')
523
+
524
+ expect(allProviders.knowledge).toContain('knowledge.notion')
525
+
526
+ expect(allProviders.media).toContain('media.cloudinary')
527
+
528
+ expect(allProviders.form).toContain('form.typeform')
529
+
530
+ expect(allProviders.analytics).toContain('analytics.mixpanel')
531
+
532
+ expect(allProviders.meeting).toContain('meeting.zoom')
533
+ expect(allProviders.meeting).toContain('meeting.google-meet')
534
+ expect(allProviders.meeting).toContain('meeting.teams')
535
+ expect(allProviders.meeting).toContain('meeting.jitsi')
536
+
537
+ expect(allProviders.storage).toContain('storage.s3')
538
+ })
539
+
540
+ it('has category keys for all provider types', () => {
541
+ const categories = Object.keys(allProviders)
542
+
543
+ expect(categories).toContain('email')
544
+ expect(categories).toContain('messaging')
545
+ expect(categories).toContain('calendar')
546
+ expect(categories).toContain('task')
547
+ expect(categories).toContain('project')
548
+ expect(categories).toContain('code')
549
+ expect(categories).toContain('sales')
550
+ expect(categories).toContain('finance')
551
+ expect(categories).toContain('support')
552
+ expect(categories).toContain('commerce')
553
+ expect(categories).toContain('knowledge')
554
+ expect(categories).toContain('media')
555
+ expect(categories).toContain('form')
556
+ expect(categories).toContain('analytics')
557
+ expect(categories).toContain('document')
558
+ expect(categories).toContain('spreadsheet')
559
+ expect(categories).toContain('presentation')
560
+ expect(categories).toContain('meeting')
561
+ expect(categories).toContain('storage')
562
+ expect(categories).toContain('signature')
563
+ })
564
+ })
565
+
566
+ // Helper function to create mock providers for testing
567
+ function createMockProvider(info: ProviderInfo): BaseProvider {
568
+ return {
569
+ info,
570
+ initialize: async (config: ProviderConfig) => {},
571
+ healthCheck: async (): Promise<ProviderHealth> => ({
572
+ healthy: true,
573
+ latencyMs: 10,
574
+ checkedAt: new Date(),
575
+ }),
576
+ dispose: async () => {},
577
+ }
578
+ }