emulate 0.4.1 → 0.6.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 (50) hide show
  1. package/README.md +198 -27
  2. package/dist/api.d.ts +2 -1
  3. package/dist/api.js +675 -103
  4. package/dist/api.js.map +1 -1
  5. package/dist/chunk-WVQMFHQM.js +83 -0
  6. package/dist/chunk-WVQMFHQM.js.map +1 -0
  7. package/dist/{dist-B674PYKV.js → dist-2ZZGNPJI.js} +22 -43
  8. package/dist/dist-2ZZGNPJI.js.map +1 -0
  9. package/dist/{dist-RDFBZ5O6.js → dist-CXRPM6BK.js} +211 -48
  10. package/dist/dist-CXRPM6BK.js.map +1 -0
  11. package/dist/{dist-VVXVP5EZ.js → dist-DSJSF3GY.js} +551 -91
  12. package/dist/dist-DSJSF3GY.js.map +1 -0
  13. package/dist/{dist-RMK3BS5M.js → dist-IFULY5LE.js} +196 -33
  14. package/dist/dist-IFULY5LE.js.map +1 -0
  15. package/dist/dist-IRUBHCZU.js +1898 -0
  16. package/dist/dist-IRUBHCZU.js.map +1 -0
  17. package/dist/{dist-YOVM5HEY.js → dist-NJJLJT2N.js} +520 -61
  18. package/dist/dist-NJJLJT2N.js.map +1 -0
  19. package/dist/dist-OGSAVJ25.js +4874 -0
  20. package/dist/dist-OGSAVJ25.js.map +1 -0
  21. package/dist/{dist-H6JYGQM4.js → dist-PO4CL5SJ.js} +271 -158
  22. package/dist/dist-PO4CL5SJ.js.map +1 -0
  23. package/dist/{dist-QMOJM6DV.js → dist-R3TNKUIE.js} +238 -55
  24. package/dist/dist-R3TNKUIE.js.map +1 -0
  25. package/dist/{dist-6JFNJPUU.js → dist-WACHAAVU.js} +171 -22
  26. package/dist/dist-WACHAAVU.js.map +1 -0
  27. package/dist/{dist-OTJZRQ3Q.js → dist-XWWZVLQQ.js} +216 -75
  28. package/dist/dist-XWWZVLQQ.js.map +1 -0
  29. package/dist/{dist-6EW7SSOZ.js → dist-ZY5SZSJ2.js} +397 -223
  30. package/dist/dist-ZY5SZSJ2.js.map +1 -0
  31. package/dist/fonts/favicon.ico +0 -0
  32. package/dist/helpers-LXLP3DFE-LBOTATT5.js +17 -0
  33. package/dist/helpers-LXLP3DFE-LBOTATT5.js.map +1 -0
  34. package/dist/index.js +812 -117
  35. package/dist/index.js.map +1 -1
  36. package/package.json +17 -15
  37. package/dist/chunk-TEPNEZ63.js +0 -2143
  38. package/dist/chunk-TEPNEZ63.js.map +0 -1
  39. package/dist/dist-6EW7SSOZ.js.map +0 -1
  40. package/dist/dist-6JFNJPUU.js.map +0 -1
  41. package/dist/dist-B674PYKV.js.map +0 -1
  42. package/dist/dist-G7WQPZ3Y.js +0 -1287
  43. package/dist/dist-G7WQPZ3Y.js.map +0 -1
  44. package/dist/dist-H6JYGQM4.js.map +0 -1
  45. package/dist/dist-OTJZRQ3Q.js.map +0 -1
  46. package/dist/dist-QMOJM6DV.js.map +0 -1
  47. package/dist/dist-RDFBZ5O6.js.map +0 -1
  48. package/dist/dist-RMK3BS5M.js.map +0 -1
  49. package/dist/dist-VVXVP5EZ.js.map +0 -1
  50. package/dist/dist-YOVM5HEY.js.map +0 -1
@@ -1,5 +1,3 @@
1
- import "./chunk-TEPNEZ63.js";
2
-
3
1
  // ../@emulators/resend/dist/index.js
4
2
  import { randomUUID } from "crypto";
5
3
  import { randomBytes } from "crypto";
@@ -93,8 +91,18 @@ function emailRoutes(ctx) {
93
91
  last_event: status === "scheduled" ? "email.scheduled" : "email.delivered"
94
92
  });
95
93
  if (!scheduledAt) {
96
- await webhooks.dispatch("email.sent", void 0, { type: "email.sent", data: { email_id: uuid, to: toArray, from, subject } }, "resend");
97
- await webhooks.dispatch("email.delivered", void 0, { type: "email.delivered", data: { email_id: uuid, to: toArray, from, subject } }, "resend");
94
+ await webhooks.dispatch(
95
+ "email.sent",
96
+ void 0,
97
+ { type: "email.sent", data: { email_id: uuid, to: toArray, from, subject } },
98
+ "resend"
99
+ );
100
+ await webhooks.dispatch(
101
+ "email.delivered",
102
+ void 0,
103
+ { type: "email.delivered", data: { email_id: uuid, to: toArray, from, subject } },
104
+ "resend"
105
+ );
98
106
  }
99
107
  results.push({ id: uuid });
100
108
  }
@@ -129,8 +137,18 @@ function emailRoutes(ctx) {
129
137
  last_event: status === "scheduled" ? "email.scheduled" : "email.delivered"
130
138
  });
131
139
  if (!scheduledAt) {
132
- await webhooks.dispatch("email.sent", void 0, { type: "email.sent", data: { email_id: uuid, to: toArray, from, subject } }, "resend");
133
- await webhooks.dispatch("email.delivered", void 0, { type: "email.delivered", data: { email_id: uuid, to: toArray, from, subject } }, "resend");
140
+ await webhooks.dispatch(
141
+ "email.sent",
142
+ void 0,
143
+ { type: "email.sent", data: { email_id: uuid, to: toArray, from, subject } },
144
+ "resend"
145
+ );
146
+ await webhooks.dispatch(
147
+ "email.delivered",
148
+ void 0,
149
+ { type: "email.delivered", data: { email_id: uuid, to: toArray, from, subject } },
150
+ "resend"
151
+ );
134
152
  }
135
153
  return c.json({ id: uuid }, 200);
136
154
  });
@@ -227,7 +245,12 @@ function domainRoutes(ctx) {
227
245
  region,
228
246
  records
229
247
  });
230
- await webhooks.dispatch("domain.created", void 0, { type: "domain.created", data: { id: uuid, name } }, "resend");
248
+ await webhooks.dispatch(
249
+ "domain.created",
250
+ void 0,
251
+ { type: "domain.created", data: { id: uuid, name } },
252
+ "resend"
253
+ );
231
254
  return c.json(formatDomain(domain), 200);
232
255
  });
233
256
  app.get("/domains", (c) => {
@@ -245,7 +268,12 @@ function domainRoutes(ctx) {
245
268
  const domain = rs().domains.findOneBy("uuid", id);
246
269
  if (!domain) return resendError(c, 404, "not_found", "Domain not found");
247
270
  rs().domains.delete(domain.id);
248
- await webhooks.dispatch("domain.deleted", void 0, { type: "domain.deleted", data: { id: domain.uuid, name: domain.name } }, "resend");
271
+ await webhooks.dispatch(
272
+ "domain.deleted",
273
+ void 0,
274
+ { type: "domain.deleted", data: { id: domain.uuid, name: domain.name } },
275
+ "resend"
276
+ );
249
277
  return c.json({ object: "domain", id: domain.uuid, deleted: true });
250
278
  });
251
279
  app.post("/domains/:id/verify", (c) => {
@@ -285,18 +313,25 @@ function apiKeyRoutes(ctx) {
285
313
  name,
286
314
  token
287
315
  });
288
- return c.json({
289
- id: apiKey.uuid,
290
- token: apiKey.token
291
- }, 200);
316
+ return c.json(
317
+ {
318
+ id: apiKey.uuid,
319
+ token: apiKey.token
320
+ },
321
+ 200
322
+ );
292
323
  });
293
324
  app.get("/api-keys", (c) => {
294
325
  const allKeys = rs().apiKeys.all();
295
- return c.json(resendList(allKeys.map((key) => ({
296
- id: key.uuid,
297
- name: key.name,
298
- created_at: key.created_at
299
- }))));
326
+ return c.json(
327
+ resendList(
328
+ allKeys.map((key) => ({
329
+ id: key.uuid,
330
+ name: key.name,
331
+ created_at: key.created_at
332
+ }))
333
+ )
334
+ );
300
335
  });
301
336
  app.delete("/api-keys/:id", (c) => {
302
337
  const id = c.req.param("id");
@@ -315,21 +350,28 @@ function contactRoutes(ctx) {
315
350
  if (!name) return resendError(c, 422, "validation_error", "Missing required field: name");
316
351
  const uuid = generateUuid();
317
352
  const audience = rs().audiences.insert({ uuid, name });
318
- return c.json({
319
- id: audience.uuid,
320
- object: "audience",
321
- name: audience.name,
322
- created_at: audience.created_at
323
- }, 200);
353
+ return c.json(
354
+ {
355
+ id: audience.uuid,
356
+ object: "audience",
357
+ name: audience.name,
358
+ created_at: audience.created_at
359
+ },
360
+ 200
361
+ );
324
362
  });
325
363
  app.get("/audiences", (c) => {
326
364
  const allAudiences = rs().audiences.all();
327
- return c.json(resendList(allAudiences.map((a) => ({
328
- id: a.uuid,
329
- object: "audience",
330
- name: a.name,
331
- created_at: a.created_at
332
- }))));
365
+ return c.json(
366
+ resendList(
367
+ allAudiences.map((a) => ({
368
+ id: a.uuid,
369
+ object: "audience",
370
+ name: a.name,
371
+ created_at: a.created_at
372
+ }))
373
+ )
374
+ );
333
375
  });
334
376
  app.delete("/audiences/:id", (c) => {
335
377
  const id = c.req.param("id");
@@ -354,27 +396,39 @@ function contactRoutes(ctx) {
354
396
  last_name: body.last_name ?? null,
355
397
  unsubscribed: body.unsubscribed ?? false
356
398
  });
357
- await webhooks.dispatch("contact.created", void 0, { type: "contact.created", data: { id: uuid, email, audience_id: audienceId } }, "resend");
358
- return c.json({
359
- id: contact.uuid,
360
- object: "contact",
361
- email: contact.email
362
- }, 200);
399
+ await webhooks.dispatch(
400
+ "contact.created",
401
+ void 0,
402
+ { type: "contact.created", data: { id: uuid, email, audience_id: audienceId } },
403
+ "resend"
404
+ );
405
+ return c.json(
406
+ {
407
+ id: contact.uuid,
408
+ object: "contact",
409
+ email: contact.email
410
+ },
411
+ 200
412
+ );
363
413
  });
364
414
  app.get("/audiences/:audience_id/contacts", (c) => {
365
415
  const audienceId = c.req.param("audience_id");
366
416
  const audience = rs().audiences.findOneBy("uuid", audienceId);
367
417
  if (!audience) return resendError(c, 404, "not_found", "Audience not found");
368
418
  const contacts = rs().contacts.findBy("audience_id", audienceId);
369
- return c.json(resendList(contacts.map((ct) => ({
370
- id: ct.uuid,
371
- object: "contact",
372
- email: ct.email,
373
- first_name: ct.first_name,
374
- last_name: ct.last_name,
375
- unsubscribed: ct.unsubscribed,
376
- created_at: ct.created_at
377
- }))));
419
+ return c.json(
420
+ resendList(
421
+ contacts.map((ct) => ({
422
+ id: ct.uuid,
423
+ object: "contact",
424
+ email: ct.email,
425
+ first_name: ct.first_name,
426
+ last_name: ct.last_name,
427
+ unsubscribed: ct.unsubscribed,
428
+ created_at: ct.created_at
429
+ }))
430
+ )
431
+ );
378
432
  });
379
433
  app.delete("/audiences/:audience_id/contacts/:id", async (c) => {
380
434
  const audienceId = c.req.param("audience_id");
@@ -384,7 +438,12 @@ function contactRoutes(ctx) {
384
438
  return resendError(c, 404, "not_found", "Contact not found");
385
439
  }
386
440
  rs().contacts.delete(contact.id);
387
- await webhooks.dispatch("contact.deleted", void 0, { type: "contact.deleted", data: { id: contact.uuid, email: contact.email, audience_id: audienceId } }, "resend");
441
+ await webhooks.dispatch(
442
+ "contact.deleted",
443
+ void 0,
444
+ { type: "contact.deleted", data: { id: contact.uuid, email: contact.email, audience_id: audienceId } },
445
+ "resend"
446
+ );
388
447
  return c.json({ object: "contact", id: contact.uuid, deleted: true });
389
448
  });
390
449
  }
@@ -403,6 +462,7 @@ var FONTS = {
403
462
  "geist-sans.woff2": readFileSync(join(__dirname, "fonts", "geist-sans.woff2")),
404
463
  "GeistPixel-Square.woff2": readFileSync(join(__dirname, "fonts", "GeistPixel-Square.woff2"))
405
464
  };
465
+ var FAVICON = readFileSync(join(__dirname, "fonts", "favicon.ico"));
406
466
  function escapeHtml(s) {
407
467
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
408
468
  }
@@ -554,6 +614,132 @@ body{
554
614
  .app-link-name{font-weight:600;font-size:.875rem;color:#33ff00;}
555
615
  .app-link-scopes{font-size:.6875rem;color:#1a8c00;margin-top:1px;}
556
616
  .empty{color:#1a8c00;text-align:center;padding:28px 0;font-size:.875rem;}
617
+
618
+ .inspector-layout{max-width:960px;margin:0 auto;padding:28px 20px;}
619
+ .inspector-tabs{display:flex;gap:4px;margin-bottom:20px;}
620
+ .inspector-tabs a{
621
+ padding:7px 16px;border-radius:6px;text-decoration:none;
622
+ font-size:.8125rem;color:#1a8c00;border:1px solid transparent;
623
+ transition:color .15s,border-color .15s;
624
+ }
625
+ .inspector-tabs a:hover{color:#33ff00;}
626
+ .inspector-tabs a.active{color:#33ff00;font-weight:600;border-color:#0a3300;background:#0a3300;}
627
+ .inspector-section{margin-bottom:24px;}
628
+ .inspector-section h2{
629
+ font-family:'Geist Pixel',monospace;
630
+ font-size:1rem;font-weight:600;color:#33ff00;margin-bottom:10px;
631
+ }
632
+ .inspector-section h3{
633
+ font-family:'Geist Pixel',monospace;
634
+ font-size:.875rem;font-weight:600;color:#1a8c00;margin:16px 0 8px;
635
+ }
636
+ .inspector-table{width:100%;border-collapse:collapse;margin-bottom:12px;}
637
+ .inspector-table th,.inspector-table td{
638
+ text-align:left;padding:8px 12px;border-bottom:1px solid #0a3300;
639
+ font-size:.8125rem;
640
+ }
641
+ .inspector-table th{color:#1a8c00;font-weight:600;font-size:.75rem;text-transform:uppercase;letter-spacing:.04em;}
642
+ .inspector-table td{color:#33ff00;}
643
+ .inspector-table tbody tr{transition:background .1s;}
644
+ .inspector-table tbody tr:hover{background:#0a3300;}
645
+ .inspector-empty{color:#1a8c00;text-align:center;padding:20px 0;font-size:.8125rem;}
646
+
647
+ .checkout-layout{
648
+ display:flex;min-height:calc(100vh - 42px);
649
+ }
650
+ .checkout-summary{
651
+ flex:1;background:#020;padding:48px 40px 48px 10%;
652
+ display:flex;flex-direction:column;justify-content:center;
653
+ border-right:1px solid #0a3300;
654
+ }
655
+ .checkout-form-side{
656
+ flex:1;background:#000;padding:48px 10% 48px 40px;
657
+ display:flex;flex-direction:column;justify-content:center;
658
+ }
659
+ .checkout-merchant{
660
+ display:flex;align-items:center;gap:10px;margin-bottom:6px;
661
+ }
662
+ .checkout-merchant-name{
663
+ font-family:'Geist Pixel',monospace;
664
+ font-size:.9375rem;font-weight:600;color:#33ff00;
665
+ }
666
+ .checkout-test-badge{
667
+ font-size:.625rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
668
+ background:#0a3300;color:#1a8c00;padding:2px 8px;border-radius:4px;
669
+ }
670
+ .checkout-total{
671
+ font-family:'Geist Pixel',monospace;
672
+ font-size:2rem;font-weight:700;color:#33ff00;margin:8px 0 28px;
673
+ }
674
+ .checkout-line-item{
675
+ display:flex;align-items:center;gap:14px;padding:14px 0;
676
+ border-bottom:1px solid #0a3300;
677
+ }
678
+ .checkout-line-item:first-child{border-top:1px solid #0a3300;}
679
+ .checkout-item-icon{
680
+ width:42px;height:42px;border-radius:6px;background:#0a3300;
681
+ display:flex;align-items:center;justify-content:center;flex-shrink:0;
682
+ font-family:'Geist Pixel',monospace;font-size:.875rem;font-weight:700;color:#116600;
683
+ }
684
+ .checkout-item-details{flex:1;min-width:0;}
685
+ .checkout-item-name{font-size:.875rem;font-weight:600;color:#33ff00;}
686
+ .checkout-item-qty{font-size:.75rem;color:#1a8c00;margin-top:2px;}
687
+ .checkout-item-price{
688
+ font-size:.875rem;font-weight:600;color:#33ff00;text-align:right;white-space:nowrap;
689
+ }
690
+ .checkout-item-unit{font-size:.6875rem;color:#1a8c00;text-align:right;margin-top:2px;}
691
+ .checkout-totals{margin-top:20px;}
692
+ .checkout-totals-row{
693
+ display:flex;justify-content:space-between;padding:6px 0;
694
+ font-size:.8125rem;color:#1a8c00;
695
+ }
696
+ .checkout-totals-row.total{
697
+ border-top:1px solid #0a3300;margin-top:8px;padding-top:14px;
698
+ font-size:.9375rem;font-weight:600;color:#33ff00;
699
+ }
700
+ .checkout-form-section{margin-bottom:24px;}
701
+ .checkout-form-label{
702
+ font-size:.8125rem;font-weight:600;color:#33ff00;margin-bottom:8px;display:block;
703
+ }
704
+ .checkout-input{
705
+ width:100%;padding:10px 12px;border:1px solid #0a3300;border-radius:6px;
706
+ background:#020;color:#33ff00;font:inherit;font-size:.875rem;
707
+ transition:border-color .15s;outline:none;
708
+ }
709
+ .checkout-input:focus{border-color:#33ff00;}
710
+ .checkout-input::placeholder{color:#116600;}
711
+ .checkout-card-box{
712
+ border:1px solid #0a3300;border-radius:6px;padding:14px;
713
+ background:#020;
714
+ }
715
+ .checkout-card-row{
716
+ display:flex;gap:12px;margin-top:10px;
717
+ }
718
+ .checkout-card-row .checkout-input{flex:1;}
719
+ .checkout-sim-note{
720
+ font-size:.6875rem;color:#1a8c00;margin-top:10px;text-align:center;
721
+ font-style:italic;
722
+ }
723
+ .checkout-pay-btn{
724
+ width:100%;padding:14px;border:none;border-radius:8px;
725
+ background:#33ff00;color:#000;font:inherit;font-size:.9375rem;font-weight:700;
726
+ cursor:pointer;transition:background .15s;
727
+ font-family:'Geist Pixel',monospace;
728
+ }
729
+ .checkout-pay-btn:hover{background:#44ff22;}
730
+ .checkout-cancel{
731
+ text-align:center;margin-top:14px;
732
+ }
733
+ .checkout-cancel a{
734
+ color:#1a8c00;text-decoration:none;font-size:.8125rem;
735
+ transition:color .15s;
736
+ }
737
+ .checkout-cancel a:hover{color:#33ff00;}
738
+ @media(max-width:768px){
739
+ .checkout-layout{flex-direction:column;}
740
+ .checkout-summary{padding:32px 20px;border-right:none;border-bottom:1px solid #0a3300;}
741
+ .checkout-form-side{padding:32px 20px;}
742
+ }
557
743
  `;
558
744
  var POWERED_BY = `<div class="powered-by">Powered by <a href="https://emulate.dev" target="_blank" rel="noopener">emulate</a></div>`;
559
745
  function emuBar(service) {
@@ -573,6 +759,7 @@ function head(title) {
573
759
  <head>
574
760
  <meta charset="utf-8"/>
575
761
  <meta name="viewport" content="width=device-width,initial-scale=1"/>
762
+ <link rel="icon" href="/_emulate/favicon.ico"/>
576
763
  <title>${escapeHtml(title)} | emulate</title>
577
764
  <style>${CSS}</style>
578
765
  </head>`;
@@ -651,9 +838,10 @@ function inboxRoutes(ctx) {
651
838
  if (email.bcc.length > 0) {
652
839
  recipientLines.push(`<strong>Bcc:</strong> ${escapeHtml(email.bcc.join(", "))}`);
653
840
  }
654
- const previewContent = email.html ? `<iframe
655
- sandbox=""
656
- srcdoc="${escapeAttr(email.html)}"
841
+ const srcdocHtml = email.html ? escapeAttr(`<base target="_blank">${email.html}`) : null;
842
+ const previewContent = srcdocHtml ? `<iframe
843
+ sandbox="allow-popups allow-popups-to-escape-sandbox"
844
+ srcdoc="${srcdocHtml}"
657
845
  class="s-card"
658
846
  style="width:100%;min-height:300px;border:1px solid #0a3300;border-radius:8px;background:#fff;"
659
847
  ></iframe>` : email.text ? `<div class="s-card"><pre class="info-text">${escapeHtml(email.text)}</pre></div>` : `<div class="empty">No content</div>`;
@@ -675,12 +863,7 @@ ${previewContent}
675
863
  <strong>Last event:</strong> ${escapeHtml(email.last_event)}
676
864
  ${email.scheduled_at ? ` | <strong>Scheduled:</strong> ${escapeHtml(email.scheduled_at)}` : ""}
677
865
  </div>`;
678
- const html = renderCardPage(
679
- email.subject,
680
- `Email ${escapeHtml(email.uuid)}`,
681
- body,
682
- SERVICE_LABEL
683
- );
866
+ const html = renderCardPage(email.subject, `Email ${escapeHtml(email.uuid)}`, body, SERVICE_LABEL);
684
867
  return c.html(html);
685
868
  });
686
869
  }
@@ -771,4 +954,4 @@ export {
771
954
  resendPlugin,
772
955
  seedFromConfig
773
956
  };
774
- //# sourceMappingURL=dist-QMOJM6DV.js.map
957
+ //# sourceMappingURL=dist-R3TNKUIE.js.map