@drawbridge/drawbridge-utils 0.0.156 → 0.0.158

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.
@@ -114,7 +114,20 @@ const sendgrid = {
114
114
  // `headers` (optional) carries the List-Unsubscribe pair on lead-facing
115
115
  // commercial sends; omitted, the request body is byte-identical to the
116
116
  // pre-opt-out-floor shape so system mail is untouched.
117
- send : async ({ apiKey, from, headers, html, request, subject, text, to }) => {
117
+ // `args` (optional) rides out as SendGrid's custom_args and comes BACK on every
118
+ // Event Webhook event for the message. That is what makes a delivery event
119
+ // answerable: an event carries the recipient and the receiving server's
120
+ // reason, but nothing about who we sent as or why, so without these a bounce
121
+ // cannot be told from a lead send or a member one.
122
+ //
123
+ // Cheaper than the alternative, which was storing SendGrid's message id on the
124
+ // notification and joining on it — a schema-gated field, and schema-gated
125
+ // fields have to ship api-first and booted. This needs no collection to change.
126
+ //
127
+ // String values only, 10,000 bytes total (SendGrid's limit). One caveat worth
128
+ // knowing when reading events: a bounce delivered asynchronously against the
129
+ // Return-Path does not carry them.
130
+ send : async ({ apiKey, args, from, headers, html, request, subject, text, to }) => {
118
131
 
119
132
  try {
120
133
 
@@ -127,6 +140,15 @@ const sendgrid = {
127
140
 
128
141
  const sender = { name : 'Drawbridge', ...from };
129
142
 
143
+ // Coerced and pruned here rather than at every call site. SendGrid
144
+ // rejects a non-string value outright, and an absent one would come back
145
+ // as the literal "undefined" on every event it tagged.
146
+ const custom = Object.fromEntries(
147
+ Object.entries( args || {} )
148
+ .filter( ( [ , value ] ) => value !== undefined && value !== null && value !== '' )
149
+ .map( ( [ key, value ] ) => [ key, String( value ) ] )
150
+ );
151
+
130
152
  await sendWithRetry( () => sendgridRequest({
131
153
  apiKey,
132
154
  ...( request && { request }),
@@ -144,6 +166,7 @@ const sendgrid = {
144
166
  }
145
167
  ],
146
168
  from : sender,
169
+ ...( Object.keys( custom ).length && { custom_args : custom } ),
147
170
  ...( headers && { headers } ),
148
171
  personalizations : [
149
172
  {
@@ -114,7 +114,20 @@ const sendgrid = {
114
114
  // `headers` (optional) carries the List-Unsubscribe pair on lead-facing
115
115
  // commercial sends; omitted, the request body is byte-identical to the
116
116
  // pre-opt-out-floor shape so system mail is untouched.
117
- send : async ({ apiKey, from, headers, html, request, subject, text, to }) => {
117
+ // `args` (optional) rides out as SendGrid's custom_args and comes BACK on every
118
+ // Event Webhook event for the message. That is what makes a delivery event
119
+ // answerable: an event carries the recipient and the receiving server's
120
+ // reason, but nothing about who we sent as or why, so without these a bounce
121
+ // cannot be told from a lead send or a member one.
122
+ //
123
+ // Cheaper than the alternative, which was storing SendGrid's message id on the
124
+ // notification and joining on it — a schema-gated field, and schema-gated
125
+ // fields have to ship api-first and booted. This needs no collection to change.
126
+ //
127
+ // String values only, 10,000 bytes total (SendGrid's limit). One caveat worth
128
+ // knowing when reading events: a bounce delivered asynchronously against the
129
+ // Return-Path does not carry them.
130
+ send : async ({ apiKey, args, from, headers, html, request, subject, text, to }) => {
118
131
 
119
132
  try {
120
133
 
@@ -127,6 +140,15 @@ const sendgrid = {
127
140
 
128
141
  const sender = { name : 'Drawbridge', ...from };
129
142
 
143
+ // Coerced and pruned here rather than at every call site. SendGrid
144
+ // rejects a non-string value outright, and an absent one would come back
145
+ // as the literal "undefined" on every event it tagged.
146
+ const custom = Object.fromEntries(
147
+ Object.entries( args || {} )
148
+ .filter( ( [ , value ] ) => value !== undefined && value !== null && value !== '' )
149
+ .map( ( [ key, value ] ) => [ key, String( value ) ] )
150
+ );
151
+
130
152
  await sendWithRetry( () => sendgridRequest({
131
153
  apiKey,
132
154
  ...( request && { request }),
@@ -144,6 +166,7 @@ const sendgrid = {
144
166
  }
145
167
  ],
146
168
  from : sender,
169
+ ...( Object.keys( custom ).length && { custom_args : custom } ),
147
170
  ...( headers && { headers } ),
148
171
  personalizations : [
149
172
  {
package/dist/sendgrid.js CHANGED
@@ -88,11 +88,27 @@ var sendgrid = {
88
88
  // `headers` (optional) carries the List-Unsubscribe pair on lead-facing
89
89
  // commercial sends; omitted, the request body is byte-identical to the
90
90
  // pre-opt-out-floor shape so system mail is untouched.
91
- send: async ({ apiKey, from, headers, html, request: request2, subject, text, to }) => {
91
+ // `args` (optional) rides out as SendGrid's custom_args and comes BACK on every
92
+ // Event Webhook event for the message. That is what makes a delivery event
93
+ // answerable: an event carries the recipient and the receiving server's
94
+ // reason, but nothing about who we sent as or why, so without these a bounce
95
+ // cannot be told from a lead send or a member one.
96
+ //
97
+ // Cheaper than the alternative, which was storing SendGrid's message id on the
98
+ // notification and joining on it — a schema-gated field, and schema-gated
99
+ // fields have to ship api-first and booted. This needs no collection to change.
100
+ //
101
+ // String values only, 10,000 bytes total (SendGrid's limit). One caveat worth
102
+ // knowing when reading events: a bounce delivered asynchronously against the
103
+ // Return-Path does not carry them.
104
+ send: async ({ apiKey, args, from, headers, html, request: request2, subject, text, to }) => {
92
105
  var _a, _b;
93
106
  try {
94
107
  if (!(from == null ? void 0 : from.email)) throw new Error("SendGrid sender missing \u2014 pass from.email (the drawbridge provider's accountSender)");
95
108
  const sender = { name: "Drawbridge", ...from };
109
+ const custom = Object.fromEntries(
110
+ Object.entries(args || {}).filter(([, value]) => value !== void 0 && value !== null && value !== "").map(([key, value]) => [key, String(value)])
111
+ );
96
112
  await sendWithRetry(() => sendgridRequest({
97
113
  apiKey,
98
114
  ...request2 && { request: request2 },
@@ -110,6 +126,7 @@ var sendgrid = {
110
126
  }
111
127
  ],
112
128
  from: sender,
129
+ ...Object.keys(custom).length && { custom_args: custom },
113
130
  ...headers && { headers },
114
131
  personalizations: [
115
132
  {
package/package.json CHANGED
@@ -216,5 +216,5 @@
216
216
  "prepublishOnly": ". \"$HOME/.nvm/nvm.sh\" && nvm use && tsup && node --test"
217
217
  },
218
218
  "types": "dist/index.d.ts",
219
- "version": "0.0.156"
219
+ "version": "0.0.158"
220
220
  }