payload-dynamic-forms 0.0.0-stage → 0.1.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 (99) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +404 -2
  3. package/dist/access.d.ts +7 -0
  4. package/dist/access.js +10 -0
  5. package/dist/access.js.map +1 -0
  6. package/dist/collections/attachments.d.ts +6 -0
  7. package/dist/collections/attachments.js +67 -0
  8. package/dist/collections/attachments.js.map +1 -0
  9. package/dist/collections/blocks.d.ts +27 -0
  10. package/dist/collections/blocks.js +495 -0
  11. package/dist/collections/blocks.js.map +1 -0
  12. package/dist/collections/forms.d.ts +3 -0
  13. package/dist/collections/forms.js +553 -0
  14. package/dist/collections/forms.js.map +1 -0
  15. package/dist/collections/overrides.d.ts +7 -0
  16. package/dist/collections/overrides.js +49 -0
  17. package/dist/collections/overrides.js.map +1 -0
  18. package/dist/collections/ruleFields.d.ts +6 -0
  19. package/dist/collections/ruleFields.js +97 -0
  20. package/dist/collections/ruleFields.js.map +1 -0
  21. package/dist/collections/submissions.d.ts +7 -0
  22. package/dist/collections/submissions.js +225 -0
  23. package/dist/collections/submissions.js.map +1 -0
  24. package/dist/delivery/run.d.ts +36 -0
  25. package/dist/delivery/run.js +187 -0
  26. package/dist/delivery/run.js.map +1 -0
  27. package/dist/delivery/webhook.d.ts +26 -0
  28. package/dist/delivery/webhook.js +71 -0
  29. package/dist/delivery/webhook.js.map +1 -0
  30. package/dist/endpoints/public.d.ts +4 -0
  31. package/dist/endpoints/public.js +27 -0
  32. package/dist/endpoints/public.js.map +1 -0
  33. package/dist/endpoints/resend.d.ts +4 -0
  34. package/dist/endpoints/resend.js +58 -0
  35. package/dist/endpoints/resend.js.map +1 -0
  36. package/dist/endpoints/submit.d.ts +4 -0
  37. package/dist/endpoints/submit.js +320 -0
  38. package/dist/endpoints/submit.js.map +1 -0
  39. package/dist/exports/shared.d.ts +13 -0
  40. package/dist/exports/shared.js +13 -0
  41. package/dist/exports/shared.js.map +1 -0
  42. package/dist/formBlock.d.ts +13 -0
  43. package/dist/formBlock.js +25 -0
  44. package/dist/formBlock.js.map +1 -0
  45. package/dist/hooks/resendTick.d.ts +8 -0
  46. package/dist/hooks/resendTick.js +55 -0
  47. package/dist/hooks/resendTick.js.map +1 -0
  48. package/dist/hooks/validateForm.d.ts +8 -0
  49. package/dist/hooks/validateForm.js +251 -0
  50. package/dist/hooks/validateForm.js.map +1 -0
  51. package/dist/index.d.ts +18 -0
  52. package/dist/index.js +124 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/security/crypto.d.ts +2 -0
  55. package/dist/security/crypto.js +17 -0
  56. package/dist/security/crypto.js.map +1 -0
  57. package/dist/security/rateLimit.d.ts +13 -0
  58. package/dist/security/rateLimit.js +28 -0
  59. package/dist/security/rateLimit.js.map +1 -0
  60. package/dist/security/request.d.ts +3 -0
  61. package/dist/security/request.js +13 -0
  62. package/dist/security/request.js.map +1 -0
  63. package/dist/security/turnstile.d.ts +28 -0
  64. package/dist/security/turnstile.js +56 -0
  65. package/dist/security/turnstile.js.map +1 -0
  66. package/dist/server/forms.d.ts +73 -0
  67. package/dist/server/forms.js +215 -0
  68. package/dist/server/forms.js.map +1 -0
  69. package/dist/server/resend.d.ts +27 -0
  70. package/dist/server/resend.js +84 -0
  71. package/dist/server/resend.js.map +1 -0
  72. package/dist/shared/answers.d.ts +47 -0
  73. package/dist/shared/answers.js +282 -0
  74. package/dist/shared/answers.js.map +1 -0
  75. package/dist/shared/operators.d.ts +41 -0
  76. package/dist/shared/operators.js +54 -0
  77. package/dist/shared/operators.js.map +1 -0
  78. package/dist/shared/rules.d.ts +58 -0
  79. package/dist/shared/rules.js +324 -0
  80. package/dist/shared/rules.js.map +1 -0
  81. package/dist/shared/steps.d.ts +28 -0
  82. package/dist/shared/steps.js +109 -0
  83. package/dist/shared/steps.js.map +1 -0
  84. package/dist/shared/tokens.d.ts +25 -0
  85. package/dist/shared/tokens.js +96 -0
  86. package/dist/shared/tokens.js.map +1 -0
  87. package/dist/shared/types.d.ts +181 -0
  88. package/dist/shared/types.js +5 -0
  89. package/dist/shared/types.js.map +1 -0
  90. package/dist/shared/whatsapp.d.ts +20 -0
  91. package/dist/shared/whatsapp.js +26 -0
  92. package/dist/shared/whatsapp.js.map +1 -0
  93. package/dist/shared/words.d.ts +9 -0
  94. package/dist/shared/words.js +41 -0
  95. package/dist/shared/words.js.map +1 -0
  96. package/dist/types.d.ts +133 -0
  97. package/dist/types.js +3 -0
  98. package/dist/types.js.map +1 -0
  99. package/package.json +113 -4
@@ -0,0 +1,97 @@
1
+ import { MATCH_MODES, OPERATORS } from '../shared/operators.js';
2
+ /** One rule row: field key (or `key.attribute`), operator from the shared list, value. */ export function ruleRowFields() {
3
+ return [
4
+ {
5
+ type: 'row',
6
+ fields: [
7
+ {
8
+ name: 'fieldKey',
9
+ type: 'text',
10
+ admin: {
11
+ description: 'A field key, or key.attribute for an attribute of the chosen option.',
12
+ width: '40%'
13
+ },
14
+ required: true
15
+ },
16
+ {
17
+ name: 'operator',
18
+ type: 'select',
19
+ admin: {
20
+ width: '30%'
21
+ },
22
+ dbName: 'op',
23
+ defaultValue: 'equals',
24
+ // The one shared list: every rule field uses this same array.
25
+ options: OPERATORS,
26
+ required: true
27
+ },
28
+ {
29
+ name: 'value',
30
+ type: 'text',
31
+ admin: {
32
+ width: '30%'
33
+ }
34
+ }
35
+ ]
36
+ }
37
+ ];
38
+ }
39
+ function matchField() {
40
+ return {
41
+ name: 'match',
42
+ type: 'radio',
43
+ dbName: 'mt',
44
+ defaultValue: 'all',
45
+ options: MATCH_MODES
46
+ };
47
+ }
48
+ /** A show/hide rule group (`all` or `any` of its rows; empty shows). */ export function ruleGroupField(name = 'visibilityRules', label = 'Show when') {
49
+ return {
50
+ name,
51
+ type: 'group',
52
+ admin: {
53
+ description: 'Leave empty to always show.'
54
+ },
55
+ fields: [
56
+ matchField(),
57
+ {
58
+ name: 'rows',
59
+ type: 'array',
60
+ admin: {
61
+ initCollapsed: true
62
+ },
63
+ fields: ruleRowFields()
64
+ }
65
+ ],
66
+ label
67
+ };
68
+ }
69
+ export function nextStepRulesField() {
70
+ return {
71
+ name: 'nextStepRules',
72
+ type: 'array',
73
+ admin: {
74
+ condition: (data)=>data?.presentationMode === 'steps',
75
+ description: 'Step-by-step forms: the first matching rule picks the next section, else the next visible one.',
76
+ initCollapsed: true
77
+ },
78
+ fields: [
79
+ {
80
+ name: 'targetSectionKey',
81
+ type: 'text',
82
+ required: true
83
+ },
84
+ matchField(),
85
+ {
86
+ name: 'rows',
87
+ type: 'array',
88
+ admin: {
89
+ initCollapsed: true
90
+ },
91
+ fields: ruleRowFields()
92
+ }
93
+ ]
94
+ };
95
+ }
96
+
97
+ //# sourceMappingURL=ruleFields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/collections/ruleFields.ts"],"sourcesContent":["import type { Field } from 'payload'\n\nimport { MATCH_MODES, OPERATORS } from '../shared/operators.js'\n\n/** One rule row: field key (or `key.attribute`), operator from the shared list, value. */\nexport function ruleRowFields(): Field[] {\n return [\n {\n type: 'row',\n fields: [\n {\n name: 'fieldKey',\n type: 'text',\n admin: {\n description: 'A field key, or key.attribute for an attribute of the chosen option.',\n width: '40%',\n },\n required: true,\n },\n {\n name: 'operator',\n type: 'select',\n admin: { width: '30%' },\n dbName: 'op',\n defaultValue: 'equals',\n // The one shared list: every rule field uses this same array.\n options: OPERATORS as unknown as { label: string; value: string }[],\n required: true,\n },\n {\n name: 'value',\n type: 'text',\n admin: { width: '30%' },\n },\n ],\n },\n ]\n}\n\nfunction matchField(): Field {\n return {\n name: 'match',\n type: 'radio',\n dbName: 'mt',\n defaultValue: 'all',\n options: MATCH_MODES as unknown as { label: string; value: string }[],\n }\n}\n\n/** A show/hide rule group (`all` or `any` of its rows; empty shows). */\nexport function ruleGroupField(name = 'visibilityRules', label = 'Show when'): Field {\n return {\n name,\n type: 'group',\n admin: { description: 'Leave empty to always show.' },\n fields: [\n matchField(),\n {\n name: 'rows',\n type: 'array',\n admin: { initCollapsed: true },\n fields: ruleRowFields(),\n },\n ],\n label,\n }\n}\n\nexport function nextStepRulesField(): Field {\n return {\n name: 'nextStepRules',\n type: 'array',\n admin: {\n condition: (data) => data?.presentationMode === 'steps',\n description:\n 'Step-by-step forms: the first matching rule picks the next section, else the next visible one.',\n initCollapsed: true,\n },\n fields: [\n {\n name: 'targetSectionKey',\n type: 'text',\n required: true,\n },\n matchField(),\n {\n name: 'rows',\n type: 'array',\n admin: { initCollapsed: true },\n fields: ruleRowFields(),\n },\n ],\n }\n}\n"],"names":["MATCH_MODES","OPERATORS","ruleRowFields","type","fields","name","admin","description","width","required","dbName","defaultValue","options","matchField","ruleGroupField","label","initCollapsed","nextStepRulesField","condition","data","presentationMode"],"mappings":"AAEA,SAASA,WAAW,EAAEC,SAAS,QAAQ,yBAAwB;AAE/D,wFAAwF,GACxF,OAAO,SAASC;IACd,OAAO;QACL;YACEC,MAAM;YACNC,QAAQ;gBACN;oBACEC,MAAM;oBACNF,MAAM;oBACNG,OAAO;wBACLC,aAAa;wBACbC,OAAO;oBACT;oBACAC,UAAU;gBACZ;gBACA;oBACEJ,MAAM;oBACNF,MAAM;oBACNG,OAAO;wBAAEE,OAAO;oBAAM;oBACtBE,QAAQ;oBACRC,cAAc;oBACd,8DAA8D;oBAC9DC,SAASX;oBACTQ,UAAU;gBACZ;gBACA;oBACEJ,MAAM;oBACNF,MAAM;oBACNG,OAAO;wBAAEE,OAAO;oBAAM;gBACxB;aACD;QACH;KACD;AACH;AAEA,SAASK;IACP,OAAO;QACLR,MAAM;QACNF,MAAM;QACNO,QAAQ;QACRC,cAAc;QACdC,SAASZ;IACX;AACF;AAEA,sEAAsE,GACtE,OAAO,SAASc,eAAeT,OAAO,iBAAiB,EAAEU,QAAQ,WAAW;IAC1E,OAAO;QACLV;QACAF,MAAM;QACNG,OAAO;YAAEC,aAAa;QAA8B;QACpDH,QAAQ;YACNS;YACA;gBACER,MAAM;gBACNF,MAAM;gBACNG,OAAO;oBAAEU,eAAe;gBAAK;gBAC7BZ,QAAQF;YACV;SACD;QACDa;IACF;AACF;AAEA,OAAO,SAASE;IACd,OAAO;QACLZ,MAAM;QACNF,MAAM;QACNG,OAAO;YACLY,WAAW,CAACC,OAASA,MAAMC,qBAAqB;YAChDb,aACE;YACFS,eAAe;QACjB;QACAZ,QAAQ;YACN;gBACEC,MAAM;gBACNF,MAAM;gBACNM,UAAU;YACZ;YACAI;YACA;gBACER,MAAM;gBACNF,MAAM;gBACNG,OAAO;oBAAEU,eAAe;gBAAK;gBAC7BZ,QAAQF;YACV;SACD;IACH;AACF"}
@@ -0,0 +1,7 @@
1
+ import type { CollectionConfig, Endpoint } from 'payload';
2
+ import type { ResolvedOptions } from '../types.js';
3
+ export declare const SUBMISSION_STATUSES: {
4
+ label: string;
5
+ value: string;
6
+ }[];
7
+ export declare function submissionsCollection(options: ResolvedOptions, endpoints: Endpoint[]): CollectionConfig;
@@ -0,0 +1,225 @@
1
+ import { adminAccess, loggedIn, nobody } from '../access.js';
2
+ import { resendTickHook } from '../hooks/resendTick.js';
3
+ export const SUBMISSION_STATUSES = [
4
+ {
5
+ label: 'Received',
6
+ value: 'received'
7
+ },
8
+ {
9
+ label: 'Processed',
10
+ value: 'processed'
11
+ },
12
+ {
13
+ label: 'Partly failed',
14
+ value: 'partlyFailed'
15
+ },
16
+ {
17
+ label: 'Failed',
18
+ value: 'failed'
19
+ }
20
+ ];
21
+ export function submissionsCollection(options, endpoints) {
22
+ const admin = adminAccess(options.isAdmin);
23
+ return {
24
+ slug: options.slugs.submissions,
25
+ access: {
26
+ create: nobody,
27
+ delete: admin,
28
+ read: loggedIn,
29
+ update: admin
30
+ },
31
+ admin: {
32
+ defaultColumns: [
33
+ 'id',
34
+ 'form',
35
+ 'status',
36
+ 'createdAt'
37
+ ],
38
+ group: 'Forms'
39
+ },
40
+ defaultSort: '-createdAt',
41
+ endpoints,
42
+ fields: [
43
+ {
44
+ name: 'form',
45
+ type: 'relationship',
46
+ relationTo: options.slugs.forms,
47
+ required: true
48
+ },
49
+ {
50
+ name: 'status',
51
+ type: 'select',
52
+ admin: {
53
+ position: 'sidebar'
54
+ },
55
+ dbName: 'sts',
56
+ defaultValue: 'received',
57
+ options: SUBMISSION_STATUSES,
58
+ required: true
59
+ },
60
+ {
61
+ name: 'resendFailed',
62
+ type: 'checkbox',
63
+ admin: {
64
+ description: 'Tick and save to run every failed email or webhook again.',
65
+ position: 'sidebar'
66
+ },
67
+ defaultValue: false,
68
+ label: 'Resend failed deliveries'
69
+ },
70
+ {
71
+ name: 'answers',
72
+ type: 'json',
73
+ required: true
74
+ },
75
+ {
76
+ name: 'snapshot',
77
+ type: 'array',
78
+ admin: {
79
+ description: 'Each answer as worded when it was sent.',
80
+ readOnly: true
81
+ },
82
+ fields: [
83
+ {
84
+ name: 'sectionKey',
85
+ type: 'text'
86
+ },
87
+ {
88
+ name: 'sectionTitle',
89
+ type: 'text'
90
+ },
91
+ {
92
+ name: 'fieldKey',
93
+ type: 'text',
94
+ required: true
95
+ },
96
+ {
97
+ name: 'label',
98
+ type: 'text'
99
+ },
100
+ {
101
+ name: 'value',
102
+ type: 'textarea'
103
+ }
104
+ ]
105
+ },
106
+ ...options.attachments ? [
107
+ {
108
+ name: 'attachments',
109
+ type: 'relationship',
110
+ admin: {
111
+ readOnly: true
112
+ },
113
+ hasMany: true,
114
+ relationTo: options.attachments.collection
115
+ }
116
+ ] : [],
117
+ {
118
+ name: 'deliveryLog',
119
+ type: 'array',
120
+ admin: {
121
+ initCollapsed: true,
122
+ readOnly: true
123
+ },
124
+ fields: [
125
+ {
126
+ name: 'kind',
127
+ type: 'select',
128
+ dbName: 'k',
129
+ options: [
130
+ {
131
+ label: 'Email',
132
+ value: 'email'
133
+ },
134
+ {
135
+ label: 'Webhook',
136
+ value: 'webhook'
137
+ }
138
+ ],
139
+ required: true
140
+ },
141
+ {
142
+ name: 'outputId',
143
+ type: 'text'
144
+ },
145
+ {
146
+ name: 'label',
147
+ type: 'text'
148
+ },
149
+ {
150
+ name: 'target',
151
+ type: 'text'
152
+ },
153
+ {
154
+ name: 'result',
155
+ type: 'select',
156
+ dbName: 'res',
157
+ options: [
158
+ {
159
+ label: 'Success',
160
+ value: 'success'
161
+ },
162
+ {
163
+ label: 'Failed',
164
+ value: 'failed'
165
+ },
166
+ {
167
+ label: 'Skipped',
168
+ value: 'skipped'
169
+ }
170
+ ],
171
+ required: true
172
+ },
173
+ {
174
+ name: 'error',
175
+ type: 'textarea'
176
+ },
177
+ {
178
+ name: 'tries',
179
+ type: 'number'
180
+ },
181
+ {
182
+ name: 'at',
183
+ type: 'date',
184
+ admin: {
185
+ date: {
186
+ pickerAppearance: 'dayAndTime'
187
+ }
188
+ }
189
+ }
190
+ ]
191
+ },
192
+ {
193
+ name: 'metadata',
194
+ type: 'group',
195
+ admin: {
196
+ readOnly: true
197
+ },
198
+ fields: [
199
+ {
200
+ name: 'ip',
201
+ type: 'text',
202
+ admin: {
203
+ description: 'Kept only when the plugin option metadata.ip is on.'
204
+ }
205
+ },
206
+ {
207
+ name: 'userAgent',
208
+ type: 'textarea'
209
+ },
210
+ {
211
+ name: 'locale',
212
+ type: 'text'
213
+ }
214
+ ]
215
+ }
216
+ ],
217
+ hooks: {
218
+ beforeChange: [
219
+ resendTickHook(options)
220
+ ]
221
+ }
222
+ };
223
+ }
224
+
225
+ //# sourceMappingURL=submissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/collections/submissions.ts"],"sourcesContent":["import type { CollectionConfig, Endpoint } from 'payload'\n\nimport type { ResolvedOptions } from '../types.js'\n\nimport { adminAccess, loggedIn, nobody } from '../access.js'\nimport { resendTickHook } from '../hooks/resendTick.js'\n\nexport const SUBMISSION_STATUSES = [\n { label: 'Received', value: 'received' },\n { label: 'Processed', value: 'processed' },\n { label: 'Partly failed', value: 'partlyFailed' },\n { label: 'Failed', value: 'failed' },\n]\n\nexport function submissionsCollection(options: ResolvedOptions, endpoints: Endpoint[]): CollectionConfig {\n const admin = adminAccess(options.isAdmin)\n return {\n slug: options.slugs.submissions,\n access: {\n create: nobody,\n delete: admin,\n read: loggedIn,\n update: admin,\n },\n admin: {\n defaultColumns: ['id', 'form', 'status', 'createdAt'],\n group: 'Forms',\n },\n defaultSort: '-createdAt',\n endpoints,\n fields: [\n { name: 'form', type: 'relationship', relationTo: options.slugs.forms as never, required: true },\n {\n name: 'status',\n type: 'select',\n admin: { position: 'sidebar' },\n dbName: 'sts',\n defaultValue: 'received',\n options: SUBMISSION_STATUSES,\n required: true,\n },\n {\n name: 'resendFailed',\n type: 'checkbox',\n admin: { description: 'Tick and save to run every failed email or webhook again.', position: 'sidebar' },\n defaultValue: false,\n label: 'Resend failed deliveries',\n },\n { name: 'answers', type: 'json', required: true },\n {\n name: 'snapshot',\n type: 'array',\n admin: { description: 'Each answer as worded when it was sent.', readOnly: true },\n fields: [\n { name: 'sectionKey', type: 'text' },\n { name: 'sectionTitle', type: 'text' },\n { name: 'fieldKey', type: 'text', required: true },\n { name: 'label', type: 'text' },\n { name: 'value', type: 'textarea' },\n ],\n },\n ...(options.attachments\n ? [\n {\n name: 'attachments',\n type: 'relationship' as const,\n admin: { readOnly: true },\n hasMany: true,\n relationTo: options.attachments.collection as never,\n },\n ]\n : []),\n {\n name: 'deliveryLog',\n type: 'array',\n admin: { initCollapsed: true, readOnly: true },\n fields: [\n {\n name: 'kind',\n type: 'select',\n dbName: 'k',\n options: [\n { label: 'Email', value: 'email' },\n { label: 'Webhook', value: 'webhook' },\n ],\n required: true,\n },\n { name: 'outputId', type: 'text' },\n { name: 'label', type: 'text' },\n { name: 'target', type: 'text' },\n {\n name: 'result',\n type: 'select',\n dbName: 'res',\n options: [\n { label: 'Success', value: 'success' },\n { label: 'Failed', value: 'failed' },\n { label: 'Skipped', value: 'skipped' },\n ],\n required: true,\n },\n { name: 'error', type: 'textarea' },\n { name: 'tries', type: 'number' },\n { name: 'at', type: 'date', admin: { date: { pickerAppearance: 'dayAndTime' } } },\n ],\n },\n {\n name: 'metadata',\n type: 'group',\n admin: { readOnly: true },\n fields: [\n { name: 'ip', type: 'text', admin: { description: 'Kept only when the plugin option metadata.ip is on.' } },\n { name: 'userAgent', type: 'textarea' },\n { name: 'locale', type: 'text' },\n ],\n },\n ],\n hooks: {\n beforeChange: [resendTickHook(options)],\n },\n }\n}\n"],"names":["adminAccess","loggedIn","nobody","resendTickHook","SUBMISSION_STATUSES","label","value","submissionsCollection","options","endpoints","admin","isAdmin","slug","slugs","submissions","access","create","delete","read","update","defaultColumns","group","defaultSort","fields","name","type","relationTo","forms","required","position","dbName","defaultValue","description","readOnly","attachments","hasMany","collection","initCollapsed","date","pickerAppearance","hooks","beforeChange"],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { Payload, PayloadRequest } from 'payload';
2
+ import type { FormDelivery } from '../server/forms.js';
3
+ import type { Answers, PublicForm, SnapshotRow, SubmissionStatus } from '../shared/types.js';
4
+ import type { ResolvedOptions } from '../types.js';
5
+ export type LogEntry = {
6
+ at: string;
7
+ error?: null | string;
8
+ kind: 'email' | 'webhook';
9
+ label?: null | string;
10
+ outputId?: null | string;
11
+ result: 'failed' | 'skipped' | 'success';
12
+ target?: null | string;
13
+ tries?: null | number;
14
+ };
15
+ export type DeliveryContext = {
16
+ answers: Answers;
17
+ attachments?: Array<{
18
+ fieldKey: string;
19
+ filename: string;
20
+ id: number | string;
21
+ }>;
22
+ delivery: FormDelivery;
23
+ form: PublicForm;
24
+ options: ResolvedOptions;
25
+ payload: Payload;
26
+ req: PayloadRequest;
27
+ snapshot: SnapshotRow[];
28
+ submissionId?: number | string;
29
+ };
30
+ /** Runs the enabled email and webhook outputs (or only `only`), each catching its own errors. */
31
+ export declare function runDeliveries(ctx: DeliveryContext, only?: Set<string>): Promise<LogEntry[]>;
32
+ export declare function hasDeliveries(delivery: FormDelivery): boolean;
33
+ /** The last entry of each output, ignoring outputs whose last entry is "skipped". */
34
+ export declare function lastResults(log: LogEntry[]): Map<string, LogEntry>;
35
+ /** processed: all succeeded or none ran; partlyFailed: some failed; failed: all failed. */
36
+ export declare function statusFromLog(log: LogEntry[]): SubmissionStatus;
@@ -0,0 +1,187 @@
1
+ import { isValidEmail } from '../shared/answers.js';
2
+ import { buildMessageRows, buildTemplateValues, interpolate } from '../shared/tokens.js';
3
+ import { sendWebhook } from './webhook.js';
4
+ function addresses(value) {
5
+ const list = String(value || '').split(/[,;]/).map((v)=>v.trim()).filter(Boolean);
6
+ return list.length ? list.join(', ') : undefined;
7
+ }
8
+ function errorText(error) {
9
+ return error instanceof Error ? error.message : String(error);
10
+ }
11
+ async function sendOneEmail(ctx, output) {
12
+ const at = new Date().toISOString();
13
+ const base = {
14
+ at,
15
+ kind: 'email',
16
+ label: output.label || null,
17
+ outputId: output.id || null
18
+ };
19
+ let to;
20
+ if (output.kind === 'visitor') {
21
+ const answer = ctx.answers[String(output.visitorField || '')];
22
+ const address = typeof answer === 'string' ? answer.trim() : '';
23
+ if (!isValidEmail(address)) {
24
+ return {
25
+ ...base,
26
+ error: `Visitor copy not sent: "${address}" is not one valid email address.`,
27
+ result: 'failed',
28
+ target: address || null,
29
+ tries: 0
30
+ };
31
+ }
32
+ to = address;
33
+ } else {
34
+ to = addresses(output.to);
35
+ }
36
+ if (!to) {
37
+ return {
38
+ ...base,
39
+ error: 'No address to send to.',
40
+ result: 'failed',
41
+ target: null,
42
+ tries: 0
43
+ };
44
+ }
45
+ const rows = buildMessageRows(ctx.form, ctx.answers, ctx.options.fieldTypes);
46
+ const values = buildTemplateValues(ctx.form, ctx.answers, {
47
+ formTitle: ctx.form.title,
48
+ submissionId: ctx.submissionId === undefined ? '' : String(ctx.submissionId)
49
+ }, ctx.options.fieldTypes);
50
+ const body = output.body || '{{*:table}}';
51
+ const replyKey = String(output.replyToField || '');
52
+ const replyTo = replyKey && isValidEmail(ctx.answers[replyKey]) ? String(ctx.answers[replyKey]).trim() : undefined;
53
+ let message = {
54
+ bcc: addresses(output.bcc),
55
+ cc: addresses(output.cc),
56
+ from: output.from?.trim() || undefined,
57
+ html: interpolate(body.split('\n').join('<br>\n'), values, {
58
+ html: true,
59
+ rows
60
+ }),
61
+ replyTo,
62
+ subject: interpolate(output.subject || 'New submission: {{formTitle}}', values, {
63
+ singleLine: true
64
+ }),
65
+ text: interpolate(body, values, {
66
+ rows
67
+ }),
68
+ to
69
+ };
70
+ for (const key of Object.keys(message)){
71
+ if (message[key] === undefined) {
72
+ delete message[key];
73
+ }
74
+ }
75
+ try {
76
+ if (ctx.options.beforeEmail) {
77
+ message = await ctx.options.beforeEmail(message, {
78
+ answers: ctx.answers,
79
+ form: ctx.form,
80
+ req: ctx.req
81
+ });
82
+ }
83
+ await ctx.payload.sendEmail(message);
84
+ return {
85
+ ...base,
86
+ result: 'success',
87
+ target: to,
88
+ tries: 1
89
+ };
90
+ } catch (error) {
91
+ return {
92
+ ...base,
93
+ error: errorText(error),
94
+ result: 'failed',
95
+ target: to,
96
+ tries: 1
97
+ };
98
+ }
99
+ }
100
+ async function sendOneWebhook(ctx, output) {
101
+ const at = new Date().toISOString();
102
+ const body = output.payloadMode === 'answersOnly' ? {
103
+ answers: ctx.answers
104
+ } : {
105
+ answers: ctx.answers,
106
+ form: {
107
+ id: ctx.form.id,
108
+ slug: ctx.form.slug,
109
+ title: ctx.form.title
110
+ },
111
+ submission: {
112
+ id: ctx.submissionId ?? null,
113
+ attachments: ctx.attachments || [],
114
+ snapshot: ctx.snapshot
115
+ }
116
+ };
117
+ const result = await sendWebhook(output, body);
118
+ return {
119
+ at,
120
+ error: result.ok ? null : result.error || 'Webhook failed.',
121
+ kind: 'webhook',
122
+ label: output.label || null,
123
+ outputId: output.id || null,
124
+ result: result.ok ? 'success' : 'failed',
125
+ target: output.url || null,
126
+ tries: result.tries
127
+ };
128
+ }
129
+ /** Runs the enabled email and webhook outputs (or only `only`), each catching its own errors. */ export async function runDeliveries(ctx, only) {
130
+ const entries = [];
131
+ for (const output of ctx.delivery.emails){
132
+ if (output.enabled === false || only && !only.has(String(output.id))) {
133
+ continue;
134
+ }
135
+ entries.push(await sendOneEmail(ctx, output));
136
+ }
137
+ for (const output of ctx.delivery.webhooks){
138
+ if (output.enabled === false || only && !only.has(String(output.id))) {
139
+ continue;
140
+ }
141
+ try {
142
+ entries.push(await sendOneWebhook(ctx, output));
143
+ } catch (error) {
144
+ entries.push({
145
+ at: new Date().toISOString(),
146
+ error: errorText(error),
147
+ kind: 'webhook',
148
+ label: output.label || null,
149
+ outputId: output.id || null,
150
+ result: 'failed',
151
+ target: output.url || null,
152
+ tries: 0
153
+ });
154
+ }
155
+ }
156
+ return entries;
157
+ }
158
+ export function hasDeliveries(delivery) {
159
+ return delivery.emails.some((e)=>e.enabled !== false) || delivery.webhooks.some((w)=>w.enabled !== false);
160
+ }
161
+ /** The last entry of each output, ignoring outputs whose last entry is "skipped". */ export function lastResults(log) {
162
+ const last = new Map();
163
+ log.forEach((entry, index)=>{
164
+ last.set(entry.outputId || `#${index}`, entry);
165
+ });
166
+ for (const [key, entry] of last){
167
+ if (entry.result === 'skipped') {
168
+ last.delete(key);
169
+ }
170
+ }
171
+ return last;
172
+ }
173
+ /** processed: all succeeded or none ran; partlyFailed: some failed; failed: all failed. */ export function statusFromLog(log) {
174
+ const results = [
175
+ ...lastResults(log).values()
176
+ ];
177
+ if (!results.length) {
178
+ return 'processed';
179
+ }
180
+ const ok = results.filter((r)=>r.result === 'success').length;
181
+ if (ok === results.length) {
182
+ return 'processed';
183
+ }
184
+ return ok === 0 ? 'failed' : 'partlyFailed';
185
+ }
186
+
187
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/delivery/run.ts"],"sourcesContent":["import type { Payload, PayloadRequest, SendEmailOptions } from 'payload'\n\nimport type { EmailOutput, FormDelivery, WebhookOutput } from '../server/forms.js'\nimport type { Answers, PublicForm, SnapshotRow, SubmissionStatus } from '../shared/types.js'\nimport type { ResolvedOptions } from '../types.js'\n\nimport { isValidEmail } from '../shared/answers.js'\nimport { buildMessageRows, buildTemplateValues, interpolate } from '../shared/tokens.js'\nimport { sendWebhook } from './webhook.js'\n\nexport type LogEntry = {\n at: string\n error?: null | string\n kind: 'email' | 'webhook'\n label?: null | string\n outputId?: null | string\n result: 'failed' | 'skipped' | 'success'\n target?: null | string\n tries?: null | number\n}\n\nexport type DeliveryContext = {\n answers: Answers\n attachments?: Array<{ fieldKey: string; filename: string; id: number | string }>\n delivery: FormDelivery\n form: PublicForm\n options: ResolvedOptions\n payload: Payload\n req: PayloadRequest\n snapshot: SnapshotRow[]\n submissionId?: number | string\n}\n\nfunction addresses(value: null | string | undefined): string | undefined {\n const list = String(value || '')\n .split(/[,;]/)\n .map((v) => v.trim())\n .filter(Boolean)\n return list.length ? list.join(', ') : undefined\n}\n\nfunction errorText(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nasync function sendOneEmail(ctx: DeliveryContext, output: EmailOutput): Promise<LogEntry> {\n const at = new Date().toISOString()\n const base = { at, kind: 'email' as const, label: output.label || null, outputId: output.id || null }\n let to: string | undefined\n if (output.kind === 'visitor') {\n const answer = ctx.answers[String(output.visitorField || '')]\n const address = typeof answer === 'string' ? answer.trim() : ''\n if (!isValidEmail(address)) {\n return {\n ...base,\n error: `Visitor copy not sent: \"${address}\" is not one valid email address.`,\n result: 'failed',\n target: address || null,\n tries: 0,\n }\n }\n to = address\n } else {\n to = addresses(output.to)\n }\n if (!to) {\n return { ...base, error: 'No address to send to.', result: 'failed', target: null, tries: 0 }\n }\n const rows = buildMessageRows(ctx.form, ctx.answers, ctx.options.fieldTypes)\n const values = buildTemplateValues(\n ctx.form,\n ctx.answers,\n { formTitle: ctx.form.title, submissionId: ctx.submissionId === undefined ? '' : String(ctx.submissionId) },\n ctx.options.fieldTypes,\n )\n const body = output.body || '{{*:table}}'\n const replyKey = String(output.replyToField || '')\n const replyTo = replyKey && isValidEmail(ctx.answers[replyKey]) ? String(ctx.answers[replyKey]).trim() : undefined\n let message: SendEmailOptions = {\n bcc: addresses(output.bcc),\n cc: addresses(output.cc),\n from: output.from?.trim() || undefined,\n html: interpolate(body.split('\\n').join('<br>\\n'), values, { html: true, rows }),\n replyTo,\n subject: interpolate(output.subject || 'New submission: {{formTitle}}', values, { singleLine: true }),\n text: interpolate(body, values, { rows }),\n to,\n }\n for (const key of Object.keys(message) as Array<keyof SendEmailOptions>) {\n if (message[key] === undefined) {\n delete message[key]\n }\n }\n try {\n if (ctx.options.beforeEmail) {\n message = await ctx.options.beforeEmail(message, { answers: ctx.answers, form: ctx.form, req: ctx.req })\n }\n await ctx.payload.sendEmail(message)\n return { ...base, result: 'success', target: to, tries: 1 }\n } catch (error) {\n return { ...base, error: errorText(error), result: 'failed', target: to, tries: 1 }\n }\n}\n\nasync function sendOneWebhook(ctx: DeliveryContext, output: WebhookOutput): Promise<LogEntry> {\n const at = new Date().toISOString()\n const body =\n output.payloadMode === 'answersOnly'\n ? { answers: ctx.answers }\n : {\n answers: ctx.answers,\n form: { id: ctx.form.id, slug: ctx.form.slug, title: ctx.form.title },\n submission: {\n id: ctx.submissionId ?? null,\n attachments: ctx.attachments || [],\n snapshot: ctx.snapshot,\n },\n }\n const result = await sendWebhook(output, body)\n return {\n at,\n error: result.ok ? null : result.error || 'Webhook failed.',\n kind: 'webhook',\n label: output.label || null,\n outputId: output.id || null,\n result: result.ok ? 'success' : 'failed',\n target: output.url || null,\n tries: result.tries,\n }\n}\n\n/** Runs the enabled email and webhook outputs (or only `only`), each catching its own errors. */\nexport async function runDeliveries(ctx: DeliveryContext, only?: Set<string>): Promise<LogEntry[]> {\n const entries: LogEntry[] = []\n for (const output of ctx.delivery.emails) {\n if (output.enabled === false || (only && !only.has(String(output.id)))) {\n continue\n }\n entries.push(await sendOneEmail(ctx, output))\n }\n for (const output of ctx.delivery.webhooks) {\n if (output.enabled === false || (only && !only.has(String(output.id)))) {\n continue\n }\n try {\n entries.push(await sendOneWebhook(ctx, output))\n } catch (error) {\n entries.push({\n at: new Date().toISOString(),\n error: errorText(error),\n kind: 'webhook',\n label: output.label || null,\n outputId: output.id || null,\n result: 'failed',\n target: output.url || null,\n tries: 0,\n })\n }\n }\n return entries\n}\n\nexport function hasDeliveries(delivery: FormDelivery): boolean {\n return delivery.emails.some((e) => e.enabled !== false) || delivery.webhooks.some((w) => w.enabled !== false)\n}\n\n/** The last entry of each output, ignoring outputs whose last entry is \"skipped\". */\nexport function lastResults(log: LogEntry[]): Map<string, LogEntry> {\n const last = new Map<string, LogEntry>()\n log.forEach((entry, index) => {\n last.set(entry.outputId || `#${index}`, entry)\n })\n for (const [key, entry] of last) {\n if (entry.result === 'skipped') {\n last.delete(key)\n }\n }\n return last\n}\n\n/** processed: all succeeded or none ran; partlyFailed: some failed; failed: all failed. */\nexport function statusFromLog(log: LogEntry[]): SubmissionStatus {\n const results = [...lastResults(log).values()]\n if (!results.length) {\n return 'processed'\n }\n const ok = results.filter((r) => r.result === 'success').length\n if (ok === results.length) {\n return 'processed'\n }\n return ok === 0 ? 'failed' : 'partlyFailed'\n}\n"],"names":["isValidEmail","buildMessageRows","buildTemplateValues","interpolate","sendWebhook","addresses","value","list","String","split","map","v","trim","filter","Boolean","length","join","undefined","errorText","error","Error","message","sendOneEmail","ctx","output","at","Date","toISOString","base","kind","label","outputId","id","to","answer","answers","visitorField","address","result","target","tries","rows","form","options","fieldTypes","values","formTitle","title","submissionId","body","replyKey","replyToField","replyTo","bcc","cc","from","html","subject","singleLine","text","key","Object","keys","beforeEmail","req","payload","sendEmail","sendOneWebhook","payloadMode","slug","submission","attachments","snapshot","ok","url","runDeliveries","only","entries","delivery","emails","enabled","has","push","webhooks","hasDeliveries","some","e","w","lastResults","log","last","Map","forEach","entry","index","set","delete","statusFromLog","results","r"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export type WebhookSettings = {
2
+ headers?: Array<{
3
+ key?: null | string;
4
+ value?: null | string;
5
+ }> | null;
6
+ method?: 'PATCH' | 'POST' | 'PUT' | null;
7
+ retries?: null | number;
8
+ signingSecret?: null | string;
9
+ timeoutMs?: null | number;
10
+ url?: null | string;
11
+ };
12
+ export type WebhookResult = {
13
+ error?: string;
14
+ ok: boolean;
15
+ status?: number;
16
+ tries: number;
17
+ };
18
+ /** Pauses between tries: 0.5 s, 1 s, 2 s. */
19
+ export declare const RETRY_PAUSES_MS: number[];
20
+ /** `X-Form-Signature` value: `t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<body>">`. */
21
+ export declare function signWebhookBody(secret: string, body: string, now?: number): Promise<string>;
22
+ /**
23
+ * Sends one webhook: JSON body, secret headers, optional signature, a timeout per try (default
24
+ * 8 s) and up to 3 retries with growing pauses. A non-2xx answer or a timeout is a failed try.
25
+ */
26
+ export declare function sendWebhook(settings: WebhookSettings, body: unknown): Promise<WebhookResult>;