@pylonsync/functions 0.3.26 → 0.3.27

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pylonsync/functions",
3
- "version": "0.3.26",
3
+ "version": "0.3.27",
4
4
  "description": "TypeScript function runtime for pylon — defines server-side queries, mutations, and actions.",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/runtime.ts CHANGED
@@ -18,6 +18,7 @@
18
18
  import type {
19
19
  DbReader,
20
20
  DbWriter,
21
+ EmailSender,
21
22
  Stream,
22
23
  Scheduler,
23
24
  QueryCtx,
@@ -441,11 +442,33 @@ function buildScheduler(callId: string): Scheduler {
441
442
  };
442
443
  }
443
444
 
445
+ /**
446
+ * Build the email sender that round-trips through the host runtime.
447
+ *
448
+ * Each `send` emits a `send_email` protocol message; the runtime
449
+ * forwards to whatever transport PYLON_EMAIL_PROVIDER points at and
450
+ * replies success or error. Errors arrive as thrown exceptions on
451
+ * the action's await, just like every other RPC. No silent failures.
452
+ */
453
+ function buildEmail(callId: string): EmailSender {
454
+ return {
455
+ async send(to, subject, body) {
456
+ await rpc(callId, {
457
+ type: "send_email",
458
+ to,
459
+ subject,
460
+ body,
461
+ });
462
+ },
463
+ };
464
+ }
465
+
444
466
  function buildActionCtx(
445
467
  callId: string,
446
468
  auth: AuthInfo,
447
469
  stream: Stream,
448
470
  scheduler: Scheduler,
471
+ email: EmailSender,
449
472
  request?: unknown
450
473
  ): ActionCtx {
451
474
  // The host sends `request` as snake_case JSON (`raw_body`); normalize it
@@ -465,6 +488,7 @@ function buildActionCtx(
465
488
  auth,
466
489
  stream,
467
490
  scheduler,
491
+ email,
468
492
  env: process.env as Record<string, string>,
469
493
  async runQuery(fnName, args) {
470
494
  return rpc(callId, {
@@ -544,6 +568,7 @@ async function handleCall(msg: CallMessage): Promise<void> {
544
568
 
545
569
  const stream = buildStream(msg.call_id);
546
570
  const scheduler = buildScheduler(msg.call_id);
571
+ const email = buildEmail(msg.call_id);
547
572
 
548
573
  // Normalize the Rust-side auth envelope (snake_case) to the camelCase
549
574
  // shape that AuthInfo documents. Handlers read `ctx.auth.userId`; the
@@ -597,6 +622,7 @@ async function handleCall(msg: CallMessage): Promise<void> {
597
622
  auth,
598
623
  stream,
599
624
  scheduler,
625
+ email,
600
626
  (msg as unknown as { request?: unknown }).request,
601
627
  );
602
628
  break;
package/src/types.ts CHANGED
@@ -171,6 +171,27 @@ export interface Scheduler {
171
171
  cancel(scheduleId: string): Promise<void>;
172
172
  }
173
173
 
174
+ /**
175
+ * Transactional email transport.
176
+ *
177
+ * Sends through whatever provider the runtime is configured for
178
+ * (PYLON_EMAIL_PROVIDER env var → SendGrid / Resend / Stack0 / SMTP /
179
+ * webhook). Available on action ctx only — sending email is external
180
+ * I/O, not allowed in mutation transactions.
181
+ *
182
+ * The runtime owns provider config + credentials; functions only
183
+ * supply the (to, subject, body) tuple. Failures are surfaced as
184
+ * thrown errors; on success the return is void.
185
+ *
186
+ * Use cases: invite emails, password-reset hand-offs, notifications,
187
+ * digest reports. NOT for marketing email — those should go through
188
+ * a dedicated bulk transport, not the transactional path.
189
+ */
190
+ export interface EmailSender {
191
+ /** Send a plain-text email. `to` is a single address. */
192
+ send(to: string, subject: string, body: string): Promise<void>;
193
+ }
194
+
174
195
  // ---------------------------------------------------------------------------
175
196
  // Context objects — what handlers receive
176
197
  // ---------------------------------------------------------------------------
@@ -200,6 +221,8 @@ export interface ActionCtx {
200
221
  auth: AuthInfo;
201
222
  stream: Stream;
202
223
  scheduler: Scheduler;
224
+ /** Send transactional email via the runtime's configured provider. */
225
+ email: EmailSender;
203
226
  /** Environment variables / secrets. */
204
227
  env: Record<string, string>;
205
228
  /** Run a registered query within its own read transaction. */