ugly-app 0.1.547 → 0.1.548

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.
@@ -1,2 +1,2 @@
1
- export declare const CLI_VERSION = "0.1.547";
1
+ export declare const CLI_VERSION = "0.1.548";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.547";
2
+ export const CLI_VERSION = "0.1.548";
3
3
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Email.d.ts","sourceRoot":"","sources":["../../src/server/Email.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,yFAAyF;AACzF,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAMD,MAAM,WAAW,WAAW;IAC1B,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAKxD;AAgBD,wBAAgB,SAAS,IAAI,IAAI,CAEhC;AAED,wBAAgB,SAAS,IAAI,IAAI,CAEhC;AAID;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,YAAY,GAAG,oBAAoB,GAC3C,OAAO,CAAC,IAAI,CAAC,CAiEf;AAED;;;GAGG;AACH,wBAAgB,iBAAiB;kBAET;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,IAAI,CAAC;EAWpB"}
1
+ {"version":3,"file":"Email.d.ts","sourceRoot":"","sources":["../../src/server/Email.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,yFAAyF;AACzF,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAMD,MAAM,WAAW,WAAW;IAC1B,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAKxD;AAgBD,wBAAgB,SAAS,IAAI,IAAI,CAEhC;AAED,wBAAgB,SAAS,IAAI,IAAI,CAEhC;AAID;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,YAAY,GAAG,oBAAoB,GAC3C,OAAO,CAAC,IAAI,CAAC,CA2Ff;AAED;;;GAGG;AACH,wBAAgB,iBAAiB;kBAET;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,IAAI,CAAC;EAWpB"}
@@ -52,6 +52,31 @@ export async function emailSend(options) {
52
52
  if (!hasUserId && !hasTo) {
53
53
  throw new Error('[Email] Recipient is required (userId or to)');
54
54
  }
55
+ // Direct Cloudflare Email Sending API path. When the CF email creds are
56
+ // present AND we have a concrete recipient address (`to`, e.g. magic-link),
57
+ // send via Cloudflare's `/email/sending/send` endpoint instead of the
58
+ // ugly.bot email proxy. This lets a lean platform core (which drops the
59
+ // /v1/email proxy in favor of direct CF email) still send transactional
60
+ // mail. `userId`-addressed sends still route through the proxy (which
61
+ // resolves the address server-side). Pure fetch → Workers-compatible.
62
+ const cfToken = process.env['CLOUDFLARE_EMAIL_API_TOKEN'];
63
+ const cfAccount = process.env['CLOUDFLARE_ACCOUNT_ID'];
64
+ const toAddr = 'to' in options ? options.to?.trim() : undefined;
65
+ if (cfToken && cfAccount && toAddr) {
66
+ await sendViaCloudflare({
67
+ token: cfToken,
68
+ accountId: cfAccount,
69
+ ...(process.env['CLOUDFLARE_EMAIL_SENDING_DOMAIN']
70
+ ? { sendingDomain: process.env['CLOUDFLARE_EMAIL_SENDING_DOMAIN'] }
71
+ : {}),
72
+ to: toAddr,
73
+ subject: options.subject,
74
+ html: options.html,
75
+ ...(options.replyTo !== undefined ? { replyTo: options.replyTo } : {}),
76
+ ...(options.headers !== undefined ? { headers: options.headers } : {}),
77
+ });
78
+ return;
79
+ }
55
80
  const { url, token, timeoutMs } = resolveConfig();
56
81
  if (!token) {
57
82
  throw new Error('[Email] EMAIL_PROXY_TOKEN is not set. Run `npx ugly-app login` ' +
@@ -131,4 +156,47 @@ export function createEmailSender() {
131
156
  },
132
157
  };
133
158
  }
159
+ // ── Direct Cloudflare Email Sending API ─────────────────────────────────────
160
+ // Mirrors the monolith's CloudflareEmailSend: POST to
161
+ // `/accounts/{id}/email/sending/send` with a CF Email API token. Pure fetch,
162
+ // so it runs on Workers. Used by emailSend() when CF email creds are present
163
+ // (lean cores send transactional mail directly instead of via the proxy).
164
+ async function sendViaCloudflare(opts) {
165
+ // Parse "Name <email@domain>" or plain "email@domain".
166
+ const from = `noreply@${opts.sendingDomain ?? 'ugly.bot'}`;
167
+ const body = {
168
+ from, // string form (CF rejects object form when no display name)
169
+ to: opts.to,
170
+ subject: opts.subject,
171
+ html: opts.html,
172
+ };
173
+ if (opts.replyTo)
174
+ body['reply_to'] = opts.replyTo;
175
+ if (opts.headers && Object.keys(opts.headers).length > 0) {
176
+ body['headers'] = opts.headers;
177
+ }
178
+ const url = `https://api.cloudflare.com/client/v4/accounts/${opts.accountId}/email/sending/send`;
179
+ const res = await fetch(url, {
180
+ method: 'POST',
181
+ headers: {
182
+ Authorization: `Bearer ${opts.token}`,
183
+ 'Content-Type': 'application/json',
184
+ },
185
+ body: JSON.stringify(body),
186
+ });
187
+ if (!res.ok) {
188
+ let msg = `HTTP ${res.status}`;
189
+ try {
190
+ const env = (await res.json());
191
+ if (env.errors?.length)
192
+ msg = env.errors.map((e) => e.message).join('; ');
193
+ }
194
+ catch {
195
+ /* fall back to status */
196
+ }
197
+ throw new Error('[Email] Cloudflare send failed: ' + msg);
198
+ }
199
+ // eslint-disable-next-line no-console
200
+ console.log('[Email] Sent via Cloudflare', { to: opts.to, subject: opts.subject });
201
+ }
134
202
  //# sourceMappingURL=Email.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Email.js","sourceRoot":"","sources":["../../src/server/Email.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Email.js","sourceRoot":"","sources":["../../src/server/Email.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugly-app",
3
- "version": "0.1.547",
3
+ "version": "0.1.548",
4
4
  "type": "module",
5
5
  "main": "./dist/server/index.js",
6
6
  "exports": {
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.547";
2
+ export const CLI_VERSION = "0.1.548";
@@ -100,6 +100,32 @@ export async function emailSend(
100
100
  throw new Error('[Email] Recipient is required (userId or to)');
101
101
  }
102
102
 
103
+ // Direct Cloudflare Email Sending API path. When the CF email creds are
104
+ // present AND we have a concrete recipient address (`to`, e.g. magic-link),
105
+ // send via Cloudflare's `/email/sending/send` endpoint instead of the
106
+ // ugly.bot email proxy. This lets a lean platform core (which drops the
107
+ // /v1/email proxy in favor of direct CF email) still send transactional
108
+ // mail. `userId`-addressed sends still route through the proxy (which
109
+ // resolves the address server-side). Pure fetch → Workers-compatible.
110
+ const cfToken = process.env['CLOUDFLARE_EMAIL_API_TOKEN'];
111
+ const cfAccount = process.env['CLOUDFLARE_ACCOUNT_ID'];
112
+ const toAddr = 'to' in options ? options.to?.trim() : undefined;
113
+ if (cfToken && cfAccount && toAddr) {
114
+ await sendViaCloudflare({
115
+ token: cfToken,
116
+ accountId: cfAccount,
117
+ ...(process.env['CLOUDFLARE_EMAIL_SENDING_DOMAIN']
118
+ ? { sendingDomain: process.env['CLOUDFLARE_EMAIL_SENDING_DOMAIN'] }
119
+ : {}),
120
+ to: toAddr,
121
+ subject: options.subject,
122
+ html: options.html,
123
+ ...(options.replyTo !== undefined ? { replyTo: options.replyTo } : {}),
124
+ ...(options.headers !== undefined ? { headers: options.headers } : {}),
125
+ });
126
+ return;
127
+ }
128
+
103
129
  const { url, token, timeoutMs } = resolveConfig();
104
130
  if (!token) {
105
131
  throw new Error(
@@ -184,3 +210,55 @@ export function createEmailSender() {
184
210
  },
185
211
  };
186
212
  }
213
+
214
+ // ── Direct Cloudflare Email Sending API ─────────────────────────────────────
215
+ // Mirrors the monolith's CloudflareEmailSend: POST to
216
+ // `/accounts/{id}/email/sending/send` with a CF Email API token. Pure fetch,
217
+ // so it runs on Workers. Used by emailSend() when CF email creds are present
218
+ // (lean cores send transactional mail directly instead of via the proxy).
219
+ async function sendViaCloudflare(opts: {
220
+ token: string;
221
+ accountId: string;
222
+ sendingDomain?: string;
223
+ to: string;
224
+ subject: string;
225
+ html: string;
226
+ replyTo?: string;
227
+ headers?: Record<string, string>;
228
+ }): Promise<void> {
229
+ // Parse "Name <email@domain>" or plain "email@domain".
230
+ const from = `noreply@${opts.sendingDomain ?? 'ugly.bot'}`;
231
+ const body: Record<string, unknown> = {
232
+ from, // string form (CF rejects object form when no display name)
233
+ to: opts.to,
234
+ subject: opts.subject,
235
+ html: opts.html,
236
+ };
237
+ if (opts.replyTo) body['reply_to'] = opts.replyTo;
238
+ if (opts.headers && Object.keys(opts.headers).length > 0) {
239
+ body['headers'] = opts.headers;
240
+ }
241
+ const url = `https://api.cloudflare.com/client/v4/accounts/${opts.accountId}/email/sending/send`;
242
+ const res = await fetch(url, {
243
+ method: 'POST',
244
+ headers: {
245
+ Authorization: `Bearer ${opts.token}`,
246
+ 'Content-Type': 'application/json',
247
+ },
248
+ body: JSON.stringify(body),
249
+ });
250
+ if (!res.ok) {
251
+ let msg = `HTTP ${res.status}`;
252
+ try {
253
+ const env = (await res.json()) as {
254
+ errors?: { message: string }[];
255
+ };
256
+ if (env.errors?.length) msg = env.errors.map((e) => e.message).join('; ');
257
+ } catch {
258
+ /* fall back to status */
259
+ }
260
+ throw new Error('[Email] Cloudflare send failed: ' + msg);
261
+ }
262
+ // eslint-disable-next-line no-console
263
+ console.log('[Email] Sent via Cloudflare', { to: opts.to, subject: opts.subject });
264
+ }