@workbuddy/piece-workbuddy-vnext 1.0.4 → 1.0.6

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 (208) hide show
  1. package/package.json +1 -1
  2. package/src/index.d.ts.map +1 -1
  3. package/src/index.js +89 -83
  4. package/src/index.js.map +1 -1
  5. package/src/index.ts +29 -17
  6. package/src/lib/actions/agents.d.ts.map +1 -1
  7. package/src/lib/actions/agents.js +6 -4
  8. package/src/lib/actions/agents.js.map +1 -1
  9. package/src/lib/actions/agents.ts +8 -4
  10. package/src/lib/actions/attachments.d.ts.map +1 -1
  11. package/src/lib/actions/attachments.js +2 -1
  12. package/src/lib/actions/attachments.js.map +1 -1
  13. package/src/lib/actions/attachments.ts +3 -1
  14. package/src/lib/actions/{crm->-companies.d.ts → crm-companies.d.ts} +1 -1
  15. package/src/lib/actions/crm-companies.d.ts.map +1 -0
  16. package/src/lib/actions/{crm->-companies.js → crm-companies.js} +1 -1
  17. package/src/lib/actions/{crm->-invites.js.map → crm-companies.js.map} +1 -1
  18. package/src/lib/actions/{crm->-contacts.d.ts → crm-contacts.d.ts} +1 -1
  19. package/src/lib/actions/crm-contacts.d.ts.map +1 -0
  20. package/src/lib/actions/{crm->-contacts.js → crm-contacts.js} +1 -1
  21. package/src/lib/actions/crm-contacts.js.map +1 -0
  22. package/src/lib/actions/{crm->-contractors.d.ts → crm-contractors.d.ts} +1 -1
  23. package/src/lib/actions/crm-contractors.d.ts.map +1 -0
  24. package/src/lib/actions/{crm->-contractors.js → crm-contractors.js} +1 -1
  25. package/src/lib/actions/{crm->-employees.js.map → crm-contractors.js.map} +1 -1
  26. package/src/lib/actions/{crm->-customers.d.ts → crm-customers.d.ts} +1 -1
  27. package/src/lib/actions/crm-customers.d.ts.map +1 -0
  28. package/src/lib/actions/{crm->-customers.js → crm-customers.js} +1 -1
  29. package/src/lib/actions/crm-customers.js.map +1 -0
  30. package/src/lib/actions/{crm->-employees.d.ts → crm-employees.d.ts} +1 -1
  31. package/src/lib/actions/crm-employees.d.ts.map +1 -0
  32. package/src/lib/actions/{crm->-employees.js → crm-employees.js} +1 -1
  33. package/src/lib/actions/crm-employees.js.map +1 -0
  34. package/src/lib/actions/{crm->-external-users.d.ts → crm-external-users.d.ts} +1 -1
  35. package/src/lib/actions/crm-external-users.d.ts.map +1 -0
  36. package/src/lib/actions/{crm->-external-users.js → crm-external-users.js} +1 -1
  37. package/src/lib/actions/crm-external-users.js.map +1 -0
  38. package/src/lib/actions/{crm->-invites.d.ts → crm-invites.d.ts} +1 -1
  39. package/src/lib/actions/crm-invites.d.ts.map +1 -0
  40. package/src/lib/actions/{crm->-invites.js → crm-invites.js} +1 -1
  41. package/src/lib/actions/crm-invites.js.map +1 -0
  42. package/src/lib/actions/{crm->-sites.d.ts → crm-sites.d.ts} +1 -1
  43. package/src/lib/actions/crm-sites.d.ts.map +1 -0
  44. package/src/lib/actions/{crm->-sites.js → crm-sites.js} +1 -1
  45. package/src/lib/actions/crm-sites.js.map +1 -0
  46. package/src/lib/actions/{crm->-suppliers.d.ts → crm-suppliers.d.ts} +1 -1
  47. package/src/lib/actions/crm-suppliers.d.ts.map +1 -0
  48. package/src/lib/actions/{crm->-suppliers.js → crm-suppliers.js} +1 -1
  49. package/src/lib/actions/crm-suppliers.js.map +1 -0
  50. package/src/lib/actions/flags.d.ts +34 -0
  51. package/src/lib/actions/flags.d.ts.map +1 -0
  52. package/src/lib/actions/flags.js +185 -0
  53. package/src/lib/actions/flags.js.map +1 -0
  54. package/src/lib/actions/flags.ts +201 -0
  55. package/src/lib/actions/index.d.ts +18 -17
  56. package/src/lib/actions/index.d.ts.map +1 -1
  57. package/src/lib/actions/index.js +18 -17
  58. package/src/lib/actions/index.js.map +1 -1
  59. package/src/lib/actions/index.ts +18 -17
  60. package/src/lib/actions/{jobs->-activities.d.ts → jobs-activities.d.ts} +15 -5
  61. package/src/lib/actions/jobs-activities.d.ts.map +1 -0
  62. package/src/lib/actions/{jobs->-activities.js → jobs-activities.js} +110 -59
  63. package/src/lib/actions/jobs-activities.js.map +1 -0
  64. package/src/lib/actions/{jobs->-activities.ts → jobs-activities.ts} +118 -57
  65. package/src/lib/actions/{jobs->-contacts.d.ts → jobs-contacts.d.ts} +1 -1
  66. package/src/lib/actions/jobs-contacts.d.ts.map +1 -0
  67. package/src/lib/actions/{jobs->-contacts.js → jobs-contacts.js} +5 -5
  68. package/src/lib/actions/jobs-contacts.js.map +1 -0
  69. package/src/lib/actions/{jobs->-contacts.ts → jobs-contacts.ts} +4 -4
  70. package/src/lib/actions/{jobs->-files.d.ts → jobs-files.d.ts} +1 -1
  71. package/src/lib/actions/jobs-files.d.ts.map +1 -0
  72. package/src/lib/actions/{jobs->-files.js → jobs-files.js} +9 -9
  73. package/src/lib/actions/jobs-files.js.map +1 -0
  74. package/src/lib/actions/{jobs->-files.ts → jobs-files.ts} +8 -8
  75. package/src/lib/actions/{jobs->-tasks.d.ts → jobs-tasks.d.ts} +4 -2
  76. package/src/lib/actions/jobs-tasks.d.ts.map +1 -0
  77. package/src/lib/actions/{jobs->-tasks.js → jobs-tasks.js} +61 -37
  78. package/src/lib/actions/jobs-tasks.js.map +1 -0
  79. package/src/lib/actions/{jobs->-tasks.ts → jobs-tasks.ts} +64 -36
  80. package/src/lib/actions/jobs.d.ts +4 -3
  81. package/src/lib/actions/jobs.d.ts.map +1 -1
  82. package/src/lib/actions/jobs.js +90 -72
  83. package/src/lib/actions/jobs.js.map +1 -1
  84. package/src/lib/actions/jobs.ts +94 -72
  85. package/src/lib/actions/mcp.d.ts +1 -1
  86. package/src/lib/actions/mcp.d.ts.map +1 -1
  87. package/src/lib/actions/mcp.js +7 -6
  88. package/src/lib/actions/mcp.js.map +1 -1
  89. package/src/lib/actions/mcp.ts +8 -6
  90. package/src/lib/actions/settings.js +1 -1
  91. package/src/lib/actions/settings.js.map +1 -1
  92. package/src/lib/actions/settings.ts +1 -1
  93. package/src/lib/actions/{stages->-activities.d.ts → stages-activities.d.ts} +24 -5
  94. package/src/lib/actions/stages-activities.d.ts.map +1 -0
  95. package/src/lib/actions/{stages->-activities.js → stages-activities.js} +164 -68
  96. package/src/lib/actions/stages-activities.js.map +1 -0
  97. package/src/lib/actions/{stages->-activities.ts → stages-activities.ts} +172 -66
  98. package/src/lib/actions/{stages->-files.d.ts → stages-files.d.ts} +5 -1
  99. package/src/lib/actions/stages-files.d.ts.map +1 -0
  100. package/src/lib/actions/{stages->-files.js → stages-files.js} +35 -15
  101. package/src/lib/actions/stages-files.js.map +1 -0
  102. package/src/lib/actions/{stages->-files.ts → stages-files.ts} +34 -14
  103. package/src/lib/actions/{stages->-resources.d.ts → stages-resources.d.ts} +1 -1
  104. package/src/lib/actions/stages-resources.d.ts.map +1 -0
  105. package/src/lib/actions/{stages->-resources.js → stages-resources.js} +7 -5
  106. package/src/lib/actions/stages-resources.js.map +1 -0
  107. package/src/lib/actions/{stages->-resources.ts → stages-resources.ts} +8 -4
  108. package/src/lib/actions/{stages->-tasks.d.ts → stages-tasks.d.ts} +8 -2
  109. package/src/lib/actions/stages-tasks.d.ts.map +1 -0
  110. package/src/lib/actions/{stages->-tasks.js → stages-tasks.js} +91 -47
  111. package/src/lib/actions/stages-tasks.js.map +1 -0
  112. package/src/lib/actions/{stages->-tasks.ts → stages-tasks.ts} +94 -46
  113. package/src/lib/actions/stages.d.ts +6 -2
  114. package/src/lib/actions/stages.d.ts.map +1 -1
  115. package/src/lib/actions/stages.js +77 -27
  116. package/src/lib/actions/stages.js.map +1 -1
  117. package/src/lib/actions/stages.ts +88 -27
  118. package/src/lib/actions/webhooks-v2.js +15 -15
  119. package/src/lib/actions/webhooks-v2.js.map +1 -1
  120. package/src/lib/actions/webhooks-v2.ts +15 -15
  121. package/src/lib/auth.js +2 -2
  122. package/src/lib/auth.js.map +1 -1
  123. package/src/lib/auth.ts +2 -2
  124. package/src/lib/triggers/activity.d.ts.map +1 -1
  125. package/src/lib/triggers/activity.js +54 -42
  126. package/src/lib/triggers/activity.js.map +1 -1
  127. package/src/lib/triggers/activity.ts +54 -42
  128. package/src/lib/triggers/bill.d.ts +240 -48
  129. package/src/lib/triggers/bill.d.ts.map +1 -1
  130. package/src/lib/triggers/bill.js +368 -88
  131. package/src/lib/triggers/bill.js.map +1 -1
  132. package/src/lib/triggers/bill.ts +368 -88
  133. package/src/lib/triggers/invoice.d.ts +240 -48
  134. package/src/lib/triggers/invoice.d.ts.map +1 -1
  135. package/src/lib/triggers/invoice.js +368 -88
  136. package/src/lib/triggers/invoice.js.map +1 -1
  137. package/src/lib/triggers/invoice.ts +368 -88
  138. package/src/lib/triggers/job.d.ts +640 -128
  139. package/src/lib/triggers/job.d.ts.map +1 -1
  140. package/src/lib/triggers/job.js +928 -208
  141. package/src/lib/triggers/job.js.map +1 -1
  142. package/src/lib/triggers/job.ts +928 -208
  143. package/src/lib/triggers/lead.d.ts +400 -80
  144. package/src/lib/triggers/lead.d.ts.map +1 -1
  145. package/src/lib/triggers/lead.js +552 -96
  146. package/src/lib/triggers/lead.js.map +1 -1
  147. package/src/lib/triggers/lead.ts +552 -96
  148. package/src/lib/triggers/opportunity.d.ts +320 -64
  149. package/src/lib/triggers/opportunity.d.ts.map +1 -1
  150. package/src/lib/triggers/opportunity.js +456 -88
  151. package/src/lib/triggers/opportunity.js.map +1 -1
  152. package/src/lib/triggers/opportunity.ts +456 -88
  153. package/src/lib/triggers/quote.d.ts +240 -48
  154. package/src/lib/triggers/quote.d.ts.map +1 -1
  155. package/src/lib/triggers/quote.js +368 -88
  156. package/src/lib/triggers/quote.js.map +1 -1
  157. package/src/lib/triggers/quote.ts +368 -88
  158. package/src/lib/triggers/stage.d.ts +480 -96
  159. package/src/lib/triggers/stage.d.ts.map +1 -1
  160. package/src/lib/triggers/stage.js +764 -220
  161. package/src/lib/triggers/stage.js.map +1 -1
  162. package/src/lib/triggers/stage.ts +764 -220
  163. package/src/lib/triggers/task.d.ts +80 -16
  164. package/src/lib/triggers/task.d.ts.map +1 -1
  165. package/src/lib/triggers/task.js +172 -68
  166. package/src/lib/triggers/task.js.map +1 -1
  167. package/src/lib/triggers/task.ts +172 -68
  168. package/src/lib/actions/crm->-companies.d.ts.map +0 -1
  169. package/src/lib/actions/crm->-companies.js.map +0 -1
  170. package/src/lib/actions/crm->-contacts.d.ts.map +0 -1
  171. package/src/lib/actions/crm->-contacts.js.map +0 -1
  172. package/src/lib/actions/crm->-contractors.d.ts.map +0 -1
  173. package/src/lib/actions/crm->-contractors.js.map +0 -1
  174. package/src/lib/actions/crm->-customers.d.ts.map +0 -1
  175. package/src/lib/actions/crm->-customers.js.map +0 -1
  176. package/src/lib/actions/crm->-employees.d.ts.map +0 -1
  177. package/src/lib/actions/crm->-external-users.d.ts.map +0 -1
  178. package/src/lib/actions/crm->-external-users.js.map +0 -1
  179. package/src/lib/actions/crm->-invites.d.ts.map +0 -1
  180. package/src/lib/actions/crm->-sites.d.ts.map +0 -1
  181. package/src/lib/actions/crm->-sites.js.map +0 -1
  182. package/src/lib/actions/crm->-suppliers.d.ts.map +0 -1
  183. package/src/lib/actions/crm->-suppliers.js.map +0 -1
  184. package/src/lib/actions/jobs->-activities.d.ts.map +0 -1
  185. package/src/lib/actions/jobs->-activities.js.map +0 -1
  186. package/src/lib/actions/jobs->-contacts.d.ts.map +0 -1
  187. package/src/lib/actions/jobs->-contacts.js.map +0 -1
  188. package/src/lib/actions/jobs->-files.d.ts.map +0 -1
  189. package/src/lib/actions/jobs->-files.js.map +0 -1
  190. package/src/lib/actions/jobs->-tasks.d.ts.map +0 -1
  191. package/src/lib/actions/jobs->-tasks.js.map +0 -1
  192. package/src/lib/actions/stages->-activities.d.ts.map +0 -1
  193. package/src/lib/actions/stages->-activities.js.map +0 -1
  194. package/src/lib/actions/stages->-files.d.ts.map +0 -1
  195. package/src/lib/actions/stages->-files.js.map +0 -1
  196. package/src/lib/actions/stages->-resources.d.ts.map +0 -1
  197. package/src/lib/actions/stages->-resources.js.map +0 -1
  198. package/src/lib/actions/stages->-tasks.d.ts.map +0 -1
  199. package/src/lib/actions/stages->-tasks.js.map +0 -1
  200. /package/src/lib/actions/{crm->-companies.ts → crm-companies.ts} +0 -0
  201. /package/src/lib/actions/{crm->-contacts.ts → crm-contacts.ts} +0 -0
  202. /package/src/lib/actions/{crm->-contractors.ts → crm-contractors.ts} +0 -0
  203. /package/src/lib/actions/{crm->-customers.ts → crm-customers.ts} +0 -0
  204. /package/src/lib/actions/{crm->-employees.ts → crm-employees.ts} +0 -0
  205. /package/src/lib/actions/{crm->-external-users.ts → crm-external-users.ts} +0 -0
  206. /package/src/lib/actions/{crm->-invites.ts → crm-invites.ts} +0 -0
  207. /package/src/lib/actions/{crm->-sites.ts → crm-sites.ts} +0 -0
  208. /package/src/lib/actions/{crm->-suppliers.ts → crm-suppliers.ts} +0 -0
@@ -8,41 +8,136 @@ export const opportunity_created_trigger = createTrigger({
8
8
  displayName: 'Opportunity Created',
9
9
  description: 'Triggered when a new opportunity is created',
10
10
  props: {
11
- customer: Property.Array({
11
+ customer: Property.MultiSelectDropdown({
12
12
  displayName: 'Filter by Customer',
13
- description: 'Only trigger for specific customer IDs',
13
+ description: 'Only trigger for specific customer',
14
14
  required: false,
15
+ auth: workbuddyAuth,
16
+ refreshers: [],
17
+ options: async ({ auth }) => {
18
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
19
+ const token = await getAccessToken(authValue);
20
+ const baseUrl = authValue.props.baseUrl;
21
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
22
+ method: HttpMethod.GET,
23
+ url: `${baseUrl}/api/v2/public/customers`,
24
+ headers: {
25
+ Authorization: `Bearer ${token}`,
26
+ 'X-WorkBuddy-Version': '2026-01',
27
+ },
28
+ });
29
+ const items = response.body?.items || [];
30
+ return {
31
+ options: items.map((item) => ({
32
+ label: item.name,
33
+ value: item.id,
34
+ })),
35
+ };
36
+ },
15
37
  }),
16
- billingCompany: Property.Array({
38
+ billingCompany: Property.MultiSelectDropdown({
17
39
  displayName: 'Filter by Billing Company',
18
- description: 'Only trigger for specific billing company IDs',
40
+ description: 'Only trigger for specific billing company',
19
41
  required: false,
42
+ auth: workbuddyAuth,
43
+ refreshers: [],
44
+ options: async ({ auth }) => {
45
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
46
+ const token = await getAccessToken(authValue);
47
+ const baseUrl = authValue.props.baseUrl;
48
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
49
+ method: HttpMethod.GET,
50
+ url: `${baseUrl}/api/v2/public/companies`,
51
+ headers: {
52
+ Authorization: `Bearer ${token}`,
53
+ 'X-WorkBuddy-Version': '2026-01',
54
+ },
55
+ });
56
+ const items = response.body?.items || [];
57
+ return {
58
+ options: items.map((item) => ({
59
+ label: item.name,
60
+ value: item.id,
61
+ })),
62
+ };
63
+ },
20
64
  }),
21
- tag: Property.Array({
65
+ tag: Property.MultiSelectDropdown({
22
66
  displayName: 'Filter by Tags',
23
- description: 'Only trigger for specific tags IDs',
67
+ description: 'Only trigger for specific tags',
24
68
  required: false,
69
+ auth: workbuddyAuth,
70
+ refreshers: [],
71
+ options: async ({ auth }) => {
72
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
73
+ const token = await getAccessToken(authValue);
74
+ const baseUrl = authValue.props.baseUrl;
75
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
76
+ method: HttpMethod.GET,
77
+ url: `${baseUrl}/api/v2/public/settings/tags`,
78
+ headers: {
79
+ Authorization: `Bearer ${token}`,
80
+ 'X-WorkBuddy-Version': '2026-01',
81
+ },
82
+ });
83
+ const items = response.body?.items || [];
84
+ return {
85
+ options: items.map((item) => ({
86
+ label: item.name,
87
+ value: item.id,
88
+ })),
89
+ };
90
+ },
25
91
  }),
26
92
  opportunityStage: Property.Array({
27
93
  displayName: 'Filter by Stage',
28
94
  description: 'Only trigger for specific stage IDs',
29
95
  required: false,
30
96
  }),
31
- owner: Property.Array({
97
+ owner: Property.MultiSelectDropdown({
32
98
  displayName: 'Filter by Owner',
33
- description: 'Only trigger for specific owner IDs',
99
+ description: 'Only trigger for specific owner',
34
100
  required: false,
101
+ auth: workbuddyAuth,
102
+ refreshers: [],
103
+ options: async ({ auth }) => {
104
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
105
+ const token = await getAccessToken(authValue);
106
+ const baseUrl = authValue.props.baseUrl;
107
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
108
+ method: HttpMethod.GET,
109
+ url: `${baseUrl}/api/v2/public/employees`,
110
+ headers: {
111
+ Authorization: `Bearer ${token}`,
112
+ 'X-WorkBuddy-Version': '2026-01',
113
+ },
114
+ });
115
+ const items = response.body?.items || [];
116
+ return {
117
+ options: items.map((item) => ({
118
+ label: item.name,
119
+ value: item.id,
120
+ })),
121
+ };
122
+ },
35
123
  }),
36
124
  },
37
125
  sampleData: {
38
- opportunity: {
39
- id: '507f1f77bcf86cd799439011',
40
- name: 'New Project Opportunity',
41
- status: 'Open',
42
- value: 50000.0,
43
- createdAt: '2026-03-05T10:00:00.000Z',
44
- customer: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
45
- owner: { id: '507f1f77bcf86cd799439011', name: 'John Smith' },
126
+ id: 'whd_019ceacb-232b-764f-8dfd-748e1a226de2',
127
+ event: 'Opportunity Created',
128
+ action: 'create',
129
+ createdAt: '2026-03-14T05:21:47.307Z',
130
+ webhookTimestamp: 1773465707307,
131
+ data: {
132
+ opportunity: {
133
+ id: '507f1f77bcf86cd799439011',
134
+ name: 'New Project Opportunity',
135
+ status: 'Open',
136
+ value: 50000.0,
137
+ createdAt: '2026-03-05T10:00:00.000Z',
138
+ customer: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
139
+ owner: { id: '507f1f77bcf86cd799439011', name: 'John Smith' },
140
+ },
46
141
  },
47
142
  },
48
143
  type: TriggerStrategy.WEBHOOK,
@@ -58,7 +153,7 @@ export const opportunity_created_trigger = createTrigger({
58
153
  if (context.propsValue.tag?.length) filters.tag = context.propsValue.tag;
59
154
  if (context.propsValue.opportunityStage?.length) filters.opportunityStage = context.propsValue.opportunityStage;
60
155
  if (context.propsValue.owner?.length) filters.owner = context.propsValue.owner;
61
- // Register webhook with WorkBuddy v2 API (server handles upsert - reactivates if exists)
156
+ // Register webhook with WorkBuddy v2 API
62
157
  const response = await httpClient.sendRequest<{ data: { id: string } }>({
63
158
  method: HttpMethod.POST,
64
159
  url: `${baseUrl}/api/v2/public/webhooks`,
@@ -90,18 +185,15 @@ export const opportunity_created_trigger = createTrigger({
90
185
  const webhookId = await context.store.get<string>('webhookId');
91
186
 
92
187
  if (webhookId) {
93
- // Pause webhook (server keeps it for potential reactivation)
188
+ // Delete webhook to avoid stale subscriptions causing duplicate trigger deliveries
94
189
  await httpClient.sendRequest({
95
- method: HttpMethod.PATCH,
190
+ method: HttpMethod.DELETE,
96
191
  url: `${baseUrl}/api/v2/public/webhooks/${webhookId}`,
97
192
  headers: {
98
193
  Authorization: `Bearer ${token}`,
99
194
  'Content-Type': 'application/json',
100
195
  'X-WorkBuddy-Version': '2026-01',
101
196
  },
102
- body: {
103
- status: 'paused',
104
- },
105
197
  });
106
198
  }
107
199
  },
@@ -117,41 +209,136 @@ export const opportunity_updated_trigger = createTrigger({
117
209
  displayName: 'Opportunity Updated',
118
210
  description: 'Triggered when an opportunity is updated',
119
211
  props: {
120
- customer: Property.Array({
212
+ customer: Property.MultiSelectDropdown({
121
213
  displayName: 'Filter by Customer',
122
- description: 'Only trigger for specific customer IDs',
214
+ description: 'Only trigger for specific customer',
123
215
  required: false,
216
+ auth: workbuddyAuth,
217
+ refreshers: [],
218
+ options: async ({ auth }) => {
219
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
220
+ const token = await getAccessToken(authValue);
221
+ const baseUrl = authValue.props.baseUrl;
222
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
223
+ method: HttpMethod.GET,
224
+ url: `${baseUrl}/api/v2/public/customers`,
225
+ headers: {
226
+ Authorization: `Bearer ${token}`,
227
+ 'X-WorkBuddy-Version': '2026-01',
228
+ },
229
+ });
230
+ const items = response.body?.items || [];
231
+ return {
232
+ options: items.map((item) => ({
233
+ label: item.name,
234
+ value: item.id,
235
+ })),
236
+ };
237
+ },
124
238
  }),
125
- billingCompany: Property.Array({
239
+ billingCompany: Property.MultiSelectDropdown({
126
240
  displayName: 'Filter by Billing Company',
127
- description: 'Only trigger for specific billing company IDs',
241
+ description: 'Only trigger for specific billing company',
128
242
  required: false,
243
+ auth: workbuddyAuth,
244
+ refreshers: [],
245
+ options: async ({ auth }) => {
246
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
247
+ const token = await getAccessToken(authValue);
248
+ const baseUrl = authValue.props.baseUrl;
249
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
250
+ method: HttpMethod.GET,
251
+ url: `${baseUrl}/api/v2/public/companies`,
252
+ headers: {
253
+ Authorization: `Bearer ${token}`,
254
+ 'X-WorkBuddy-Version': '2026-01',
255
+ },
256
+ });
257
+ const items = response.body?.items || [];
258
+ return {
259
+ options: items.map((item) => ({
260
+ label: item.name,
261
+ value: item.id,
262
+ })),
263
+ };
264
+ },
129
265
  }),
130
- tag: Property.Array({
266
+ tag: Property.MultiSelectDropdown({
131
267
  displayName: 'Filter by Tags',
132
- description: 'Only trigger for specific tags IDs',
268
+ description: 'Only trigger for specific tags',
133
269
  required: false,
270
+ auth: workbuddyAuth,
271
+ refreshers: [],
272
+ options: async ({ auth }) => {
273
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
274
+ const token = await getAccessToken(authValue);
275
+ const baseUrl = authValue.props.baseUrl;
276
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
277
+ method: HttpMethod.GET,
278
+ url: `${baseUrl}/api/v2/public/settings/tags`,
279
+ headers: {
280
+ Authorization: `Bearer ${token}`,
281
+ 'X-WorkBuddy-Version': '2026-01',
282
+ },
283
+ });
284
+ const items = response.body?.items || [];
285
+ return {
286
+ options: items.map((item) => ({
287
+ label: item.name,
288
+ value: item.id,
289
+ })),
290
+ };
291
+ },
134
292
  }),
135
293
  opportunityStage: Property.Array({
136
294
  displayName: 'Filter by Stage',
137
295
  description: 'Only trigger for specific stage IDs',
138
296
  required: false,
139
297
  }),
140
- owner: Property.Array({
298
+ owner: Property.MultiSelectDropdown({
141
299
  displayName: 'Filter by Owner',
142
- description: 'Only trigger for specific owner IDs',
300
+ description: 'Only trigger for specific owner',
143
301
  required: false,
302
+ auth: workbuddyAuth,
303
+ refreshers: [],
304
+ options: async ({ auth }) => {
305
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
306
+ const token = await getAccessToken(authValue);
307
+ const baseUrl = authValue.props.baseUrl;
308
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
309
+ method: HttpMethod.GET,
310
+ url: `${baseUrl}/api/v2/public/employees`,
311
+ headers: {
312
+ Authorization: `Bearer ${token}`,
313
+ 'X-WorkBuddy-Version': '2026-01',
314
+ },
315
+ });
316
+ const items = response.body?.items || [];
317
+ return {
318
+ options: items.map((item) => ({
319
+ label: item.name,
320
+ value: item.id,
321
+ })),
322
+ };
323
+ },
144
324
  }),
145
325
  },
146
326
  sampleData: {
147
- opportunity: {
148
- id: '507f1f77bcf86cd799439011',
149
- name: 'New Project Opportunity',
150
- status: 'Open',
151
- value: 50000.0,
152
- createdAt: '2026-03-05T10:00:00.000Z',
153
- customer: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
154
- owner: { id: '507f1f77bcf86cd799439011', name: 'John Smith' },
327
+ id: 'whd_019ceacb-232b-764f-8dfd-748e1a226de2',
328
+ event: 'Opportunity Updated',
329
+ action: 'update',
330
+ createdAt: '2026-03-14T05:21:47.307Z',
331
+ webhookTimestamp: 1773465707307,
332
+ data: {
333
+ opportunity: {
334
+ id: '507f1f77bcf86cd799439011',
335
+ name: 'New Project Opportunity',
336
+ status: 'Open',
337
+ value: 50000.0,
338
+ createdAt: '2026-03-05T10:00:00.000Z',
339
+ customer: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
340
+ owner: { id: '507f1f77bcf86cd799439011', name: 'John Smith' },
341
+ },
155
342
  },
156
343
  },
157
344
  type: TriggerStrategy.WEBHOOK,
@@ -167,7 +354,7 @@ export const opportunity_updated_trigger = createTrigger({
167
354
  if (context.propsValue.tag?.length) filters.tag = context.propsValue.tag;
168
355
  if (context.propsValue.opportunityStage?.length) filters.opportunityStage = context.propsValue.opportunityStage;
169
356
  if (context.propsValue.owner?.length) filters.owner = context.propsValue.owner;
170
- // Register webhook with WorkBuddy v2 API (server handles upsert - reactivates if exists)
357
+ // Register webhook with WorkBuddy v2 API
171
358
  const response = await httpClient.sendRequest<{ data: { id: string } }>({
172
359
  method: HttpMethod.POST,
173
360
  url: `${baseUrl}/api/v2/public/webhooks`,
@@ -199,18 +386,15 @@ export const opportunity_updated_trigger = createTrigger({
199
386
  const webhookId = await context.store.get<string>('webhookId');
200
387
 
201
388
  if (webhookId) {
202
- // Pause webhook (server keeps it for potential reactivation)
389
+ // Delete webhook to avoid stale subscriptions causing duplicate trigger deliveries
203
390
  await httpClient.sendRequest({
204
- method: HttpMethod.PATCH,
391
+ method: HttpMethod.DELETE,
205
392
  url: `${baseUrl}/api/v2/public/webhooks/${webhookId}`,
206
393
  headers: {
207
394
  Authorization: `Bearer ${token}`,
208
395
  'Content-Type': 'application/json',
209
396
  'X-WorkBuddy-Version': '2026-01',
210
397
  },
211
- body: {
212
- status: 'paused',
213
- },
214
398
  });
215
399
  }
216
400
  },
@@ -226,41 +410,136 @@ export const opportunity_status_changed_trigger = createTrigger({
226
410
  displayName: 'Opportunity Status Changed',
227
411
  description: 'Triggered when an opportunity status changes',
228
412
  props: {
229
- customer: Property.Array({
413
+ customer: Property.MultiSelectDropdown({
230
414
  displayName: 'Filter by Customer',
231
- description: 'Only trigger for specific customer IDs',
415
+ description: 'Only trigger for specific customer',
232
416
  required: false,
417
+ auth: workbuddyAuth,
418
+ refreshers: [],
419
+ options: async ({ auth }) => {
420
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
421
+ const token = await getAccessToken(authValue);
422
+ const baseUrl = authValue.props.baseUrl;
423
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
424
+ method: HttpMethod.GET,
425
+ url: `${baseUrl}/api/v2/public/customers`,
426
+ headers: {
427
+ Authorization: `Bearer ${token}`,
428
+ 'X-WorkBuddy-Version': '2026-01',
429
+ },
430
+ });
431
+ const items = response.body?.items || [];
432
+ return {
433
+ options: items.map((item) => ({
434
+ label: item.name,
435
+ value: item.id,
436
+ })),
437
+ };
438
+ },
233
439
  }),
234
- billingCompany: Property.Array({
440
+ billingCompany: Property.MultiSelectDropdown({
235
441
  displayName: 'Filter by Billing Company',
236
- description: 'Only trigger for specific billing company IDs',
442
+ description: 'Only trigger for specific billing company',
237
443
  required: false,
444
+ auth: workbuddyAuth,
445
+ refreshers: [],
446
+ options: async ({ auth }) => {
447
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
448
+ const token = await getAccessToken(authValue);
449
+ const baseUrl = authValue.props.baseUrl;
450
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
451
+ method: HttpMethod.GET,
452
+ url: `${baseUrl}/api/v2/public/companies`,
453
+ headers: {
454
+ Authorization: `Bearer ${token}`,
455
+ 'X-WorkBuddy-Version': '2026-01',
456
+ },
457
+ });
458
+ const items = response.body?.items || [];
459
+ return {
460
+ options: items.map((item) => ({
461
+ label: item.name,
462
+ value: item.id,
463
+ })),
464
+ };
465
+ },
238
466
  }),
239
- tag: Property.Array({
467
+ tag: Property.MultiSelectDropdown({
240
468
  displayName: 'Filter by Tags',
241
- description: 'Only trigger for specific tags IDs',
469
+ description: 'Only trigger for specific tags',
242
470
  required: false,
471
+ auth: workbuddyAuth,
472
+ refreshers: [],
473
+ options: async ({ auth }) => {
474
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
475
+ const token = await getAccessToken(authValue);
476
+ const baseUrl = authValue.props.baseUrl;
477
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
478
+ method: HttpMethod.GET,
479
+ url: `${baseUrl}/api/v2/public/settings/tags`,
480
+ headers: {
481
+ Authorization: `Bearer ${token}`,
482
+ 'X-WorkBuddy-Version': '2026-01',
483
+ },
484
+ });
485
+ const items = response.body?.items || [];
486
+ return {
487
+ options: items.map((item) => ({
488
+ label: item.name,
489
+ value: item.id,
490
+ })),
491
+ };
492
+ },
243
493
  }),
244
494
  opportunityStage: Property.Array({
245
495
  displayName: 'Filter by Stage',
246
496
  description: 'Only trigger for specific stage IDs',
247
497
  required: false,
248
498
  }),
249
- owner: Property.Array({
499
+ owner: Property.MultiSelectDropdown({
250
500
  displayName: 'Filter by Owner',
251
- description: 'Only trigger for specific owner IDs',
501
+ description: 'Only trigger for specific owner',
252
502
  required: false,
503
+ auth: workbuddyAuth,
504
+ refreshers: [],
505
+ options: async ({ auth }) => {
506
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
507
+ const token = await getAccessToken(authValue);
508
+ const baseUrl = authValue.props.baseUrl;
509
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
510
+ method: HttpMethod.GET,
511
+ url: `${baseUrl}/api/v2/public/employees`,
512
+ headers: {
513
+ Authorization: `Bearer ${token}`,
514
+ 'X-WorkBuddy-Version': '2026-01',
515
+ },
516
+ });
517
+ const items = response.body?.items || [];
518
+ return {
519
+ options: items.map((item) => ({
520
+ label: item.name,
521
+ value: item.id,
522
+ })),
523
+ };
524
+ },
253
525
  }),
254
526
  },
255
527
  sampleData: {
256
- opportunity: {
257
- id: '507f1f77bcf86cd799439011',
258
- name: 'New Project Opportunity',
259
- status: 'Open',
260
- value: 50000.0,
261
- createdAt: '2026-03-05T10:00:00.000Z',
262
- customer: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
263
- owner: { id: '507f1f77bcf86cd799439011', name: 'John Smith' },
528
+ id: 'whd_019ceacb-232b-764f-8dfd-748e1a226de2',
529
+ event: 'Opportunity Status Changed',
530
+ action: 'update',
531
+ createdAt: '2026-03-14T05:21:47.307Z',
532
+ webhookTimestamp: 1773465707307,
533
+ data: {
534
+ opportunity: {
535
+ id: '507f1f77bcf86cd799439011',
536
+ name: 'New Project Opportunity',
537
+ status: 'Open',
538
+ value: 50000.0,
539
+ createdAt: '2026-03-05T10:00:00.000Z',
540
+ customer: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
541
+ owner: { id: '507f1f77bcf86cd799439011', name: 'John Smith' },
542
+ },
264
543
  },
265
544
  },
266
545
  type: TriggerStrategy.WEBHOOK,
@@ -276,7 +555,7 @@ export const opportunity_status_changed_trigger = createTrigger({
276
555
  if (context.propsValue.tag?.length) filters.tag = context.propsValue.tag;
277
556
  if (context.propsValue.opportunityStage?.length) filters.opportunityStage = context.propsValue.opportunityStage;
278
557
  if (context.propsValue.owner?.length) filters.owner = context.propsValue.owner;
279
- // Register webhook with WorkBuddy v2 API (server handles upsert - reactivates if exists)
558
+ // Register webhook with WorkBuddy v2 API
280
559
  const response = await httpClient.sendRequest<{ data: { id: string } }>({
281
560
  method: HttpMethod.POST,
282
561
  url: `${baseUrl}/api/v2/public/webhooks`,
@@ -308,18 +587,15 @@ export const opportunity_status_changed_trigger = createTrigger({
308
587
  const webhookId = await context.store.get<string>('webhookId');
309
588
 
310
589
  if (webhookId) {
311
- // Pause webhook (server keeps it for potential reactivation)
590
+ // Delete webhook to avoid stale subscriptions causing duplicate trigger deliveries
312
591
  await httpClient.sendRequest({
313
- method: HttpMethod.PATCH,
592
+ method: HttpMethod.DELETE,
314
593
  url: `${baseUrl}/api/v2/public/webhooks/${webhookId}`,
315
594
  headers: {
316
595
  Authorization: `Bearer ${token}`,
317
596
  'Content-Type': 'application/json',
318
597
  'X-WorkBuddy-Version': '2026-01',
319
598
  },
320
- body: {
321
- status: 'paused',
322
- },
323
599
  });
324
600
  }
325
601
  },
@@ -335,41 +611,136 @@ export const opportunity_deleted_trigger = createTrigger({
335
611
  displayName: 'Opportunity Deleted',
336
612
  description: 'Triggered when an opportunity is deleted',
337
613
  props: {
338
- customer: Property.Array({
614
+ customer: Property.MultiSelectDropdown({
339
615
  displayName: 'Filter by Customer',
340
- description: 'Only trigger for specific customer IDs',
616
+ description: 'Only trigger for specific customer',
341
617
  required: false,
618
+ auth: workbuddyAuth,
619
+ refreshers: [],
620
+ options: async ({ auth }) => {
621
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
622
+ const token = await getAccessToken(authValue);
623
+ const baseUrl = authValue.props.baseUrl;
624
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
625
+ method: HttpMethod.GET,
626
+ url: `${baseUrl}/api/v2/public/customers`,
627
+ headers: {
628
+ Authorization: `Bearer ${token}`,
629
+ 'X-WorkBuddy-Version': '2026-01',
630
+ },
631
+ });
632
+ const items = response.body?.items || [];
633
+ return {
634
+ options: items.map((item) => ({
635
+ label: item.name,
636
+ value: item.id,
637
+ })),
638
+ };
639
+ },
342
640
  }),
343
- billingCompany: Property.Array({
641
+ billingCompany: Property.MultiSelectDropdown({
344
642
  displayName: 'Filter by Billing Company',
345
- description: 'Only trigger for specific billing company IDs',
643
+ description: 'Only trigger for specific billing company',
346
644
  required: false,
645
+ auth: workbuddyAuth,
646
+ refreshers: [],
647
+ options: async ({ auth }) => {
648
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
649
+ const token = await getAccessToken(authValue);
650
+ const baseUrl = authValue.props.baseUrl;
651
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
652
+ method: HttpMethod.GET,
653
+ url: `${baseUrl}/api/v2/public/companies`,
654
+ headers: {
655
+ Authorization: `Bearer ${token}`,
656
+ 'X-WorkBuddy-Version': '2026-01',
657
+ },
658
+ });
659
+ const items = response.body?.items || [];
660
+ return {
661
+ options: items.map((item) => ({
662
+ label: item.name,
663
+ value: item.id,
664
+ })),
665
+ };
666
+ },
347
667
  }),
348
- tag: Property.Array({
668
+ tag: Property.MultiSelectDropdown({
349
669
  displayName: 'Filter by Tags',
350
- description: 'Only trigger for specific tags IDs',
670
+ description: 'Only trigger for specific tags',
351
671
  required: false,
672
+ auth: workbuddyAuth,
673
+ refreshers: [],
674
+ options: async ({ auth }) => {
675
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
676
+ const token = await getAccessToken(authValue);
677
+ const baseUrl = authValue.props.baseUrl;
678
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
679
+ method: HttpMethod.GET,
680
+ url: `${baseUrl}/api/v2/public/settings/tags`,
681
+ headers: {
682
+ Authorization: `Bearer ${token}`,
683
+ 'X-WorkBuddy-Version': '2026-01',
684
+ },
685
+ });
686
+ const items = response.body?.items || [];
687
+ return {
688
+ options: items.map((item) => ({
689
+ label: item.name,
690
+ value: item.id,
691
+ })),
692
+ };
693
+ },
352
694
  }),
353
695
  opportunityStage: Property.Array({
354
696
  displayName: 'Filter by Stage',
355
697
  description: 'Only trigger for specific stage IDs',
356
698
  required: false,
357
699
  }),
358
- owner: Property.Array({
700
+ owner: Property.MultiSelectDropdown({
359
701
  displayName: 'Filter by Owner',
360
- description: 'Only trigger for specific owner IDs',
702
+ description: 'Only trigger for specific owner',
361
703
  required: false,
704
+ auth: workbuddyAuth,
705
+ refreshers: [],
706
+ options: async ({ auth }) => {
707
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
708
+ const token = await getAccessToken(authValue);
709
+ const baseUrl = authValue.props.baseUrl;
710
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
711
+ method: HttpMethod.GET,
712
+ url: `${baseUrl}/api/v2/public/employees`,
713
+ headers: {
714
+ Authorization: `Bearer ${token}`,
715
+ 'X-WorkBuddy-Version': '2026-01',
716
+ },
717
+ });
718
+ const items = response.body?.items || [];
719
+ return {
720
+ options: items.map((item) => ({
721
+ label: item.name,
722
+ value: item.id,
723
+ })),
724
+ };
725
+ },
362
726
  }),
363
727
  },
364
728
  sampleData: {
365
- opportunity: {
366
- id: '507f1f77bcf86cd799439011',
367
- name: 'New Project Opportunity',
368
- status: 'Open',
369
- value: 50000.0,
370
- createdAt: '2026-03-05T10:00:00.000Z',
371
- customer: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
372
- owner: { id: '507f1f77bcf86cd799439011', name: 'John Smith' },
729
+ id: 'whd_019ceacb-232b-764f-8dfd-748e1a226de2',
730
+ event: 'Opportunity Deleted',
731
+ action: 'remove',
732
+ createdAt: '2026-03-14T05:21:47.307Z',
733
+ webhookTimestamp: 1773465707307,
734
+ data: {
735
+ opportunity: {
736
+ id: '507f1f77bcf86cd799439011',
737
+ name: 'New Project Opportunity',
738
+ status: 'Open',
739
+ value: 50000.0,
740
+ createdAt: '2026-03-05T10:00:00.000Z',
741
+ customer: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
742
+ owner: { id: '507f1f77bcf86cd799439011', name: 'John Smith' },
743
+ },
373
744
  },
374
745
  },
375
746
  type: TriggerStrategy.WEBHOOK,
@@ -385,7 +756,7 @@ export const opportunity_deleted_trigger = createTrigger({
385
756
  if (context.propsValue.tag?.length) filters.tag = context.propsValue.tag;
386
757
  if (context.propsValue.opportunityStage?.length) filters.opportunityStage = context.propsValue.opportunityStage;
387
758
  if (context.propsValue.owner?.length) filters.owner = context.propsValue.owner;
388
- // Register webhook with WorkBuddy v2 API (server handles upsert - reactivates if exists)
759
+ // Register webhook with WorkBuddy v2 API
389
760
  const response = await httpClient.sendRequest<{ data: { id: string } }>({
390
761
  method: HttpMethod.POST,
391
762
  url: `${baseUrl}/api/v2/public/webhooks`,
@@ -417,18 +788,15 @@ export const opportunity_deleted_trigger = createTrigger({
417
788
  const webhookId = await context.store.get<string>('webhookId');
418
789
 
419
790
  if (webhookId) {
420
- // Pause webhook (server keeps it for potential reactivation)
791
+ // Delete webhook to avoid stale subscriptions causing duplicate trigger deliveries
421
792
  await httpClient.sendRequest({
422
- method: HttpMethod.PATCH,
793
+ method: HttpMethod.DELETE,
423
794
  url: `${baseUrl}/api/v2/public/webhooks/${webhookId}`,
424
795
  headers: {
425
796
  Authorization: `Bearer ${token}`,
426
797
  'Content-Type': 'application/json',
427
798
  'X-WorkBuddy-Version': '2026-01',
428
799
  },
429
- body: {
430
- status: 'paused',
431
- },
432
800
  });
433
801
  }
434
802
  },