@secondlayer/shared 13.13.0 → 13.13.1

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,8 +1,14 @@
1
1
  /**
2
- * The one HTML/text layout every customer email renders through. Table-based
3
- * HTML, inline styles only (email clients strip <style>), 560px max width,
4
- * white background, #111 text, one black button — same look as the login
5
- * email this was lifted from. Text is the same content, plainer.
2
+ * The one HTML/text layout every customer email renders through, in the
3
+ * brand's "Figure" look: logo + wordmark, a 24px heading, muted prose, the
4
+ * code or facts inside a hairline code figure whose bar names it and carries
5
+ * a status chip, one blue button, and a hairline footer.
6
+ *
7
+ * Table-based HTML with inline styles (most clients strip <style>). The head
8
+ * <style> only adds dark mode for clients that honor `prefers-color-scheme`
9
+ * (Apple Mail, iOS); everyone else gets the light palette, which Gmail
10
+ * inverts on its own. Geist loads where web fonts work, the system stack
11
+ * elsewhere. Callers pass content; every color lives here.
6
12
  */
7
13
  interface FactRow {
8
14
  label: string;
@@ -12,13 +18,28 @@ interface EmailCta {
12
18
  label: string;
13
19
  url: string;
14
20
  }
21
+ /** `alarm` only for failures and stops, `ok` only for success. */
22
+ type EmailTone = "neutral" | "ok" | "alarm";
23
+ interface EmailStatus {
24
+ tone: EmailTone;
25
+ text: string;
26
+ }
15
27
  interface RenderEmailInput {
16
28
  heading: string;
29
+ /** The inbox preview line after the subject. Not shown in the body. */
30
+ preheader?: string;
17
31
  paragraphs: string[];
18
- /** A code shown in a large, letter-spaced box (login codes). */
32
+ /** Someone else's words, quoted (a contact form message). */
33
+ quote?: string;
34
+ /** A sign-in code, shown as one selectable run of digits in the figure. */
19
35
  code?: string;
20
36
  facts?: FactRow[];
37
+ /** The figure's title bar. Defaults to "sign-in code" or "details". */
38
+ figure?: string;
39
+ /** A chip in the figure bar, or a status line when there is no figure. */
40
+ status?: EmailStatus;
21
41
  cta?: EmailCta;
42
+ /** Why the reader got this email and how to stop it. */
22
43
  footnote?: string;
23
44
  }
24
45
  interface RenderedEmail {
@@ -46,4 +67,4 @@ type SendEmailResult = {
46
67
  skipped: false
47
68
  };
48
69
  declare function sendEmail(input: SendEmailInput): Promise<SendEmailResult>;
49
- export { EmailCta, FactRow, RenderEmailInput, RenderedEmail, SendEmailInput, SendEmailResult, renderEmail, sendEmail };
70
+ export { EmailCta, EmailStatus, EmailTone, FactRow, RenderEmailInput, RenderedEmail, SendEmailInput, SendEmailResult, renderEmail, sendEmail };
@@ -1,60 +1,166 @@
1
1
  // src/email/render.ts
2
+ var LOGO_URL = "https://www.secondlayer.tools/email/logo.png";
3
+ var TAGLINE = "Instant data for apps on Bitcoin";
4
+ var SANS = "Geist, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
5
+ var MONO = "'Geist Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace";
6
+ var LIGHT = {
7
+ paper: "#fbfaf7",
8
+ ink: "#14110d",
9
+ sub: "#63605c",
10
+ faint: "#9d9b97",
11
+ line: "#e8e6e3",
12
+ pri: "#1f45e0",
13
+ onPri: "#fbfaf7",
14
+ ok: "#128a43",
15
+ alarm: "#e3301e"
16
+ };
17
+ var DARK_STYLE = `
18
+ @media (prefers-color-scheme: dark) {
19
+ .sl-paper { background: #1e1b17 !important; }
20
+ .sl-ink { color: #e8e6e3 !important; }
21
+ .sl-sub { color: #b3b1ad !important; }
22
+ .sl-faint { color: #7c7a76 !important; }
23
+ .sl-line { border-color: #393632 !important; }
24
+ .sl-pri { background: #3a5bff !important; }
25
+ .sl-ok { color: #5cc28f !important; }
26
+ .sl-alarm { color: #ff5a47 !important; }
27
+ .sl-dot-neutral { background: #7c7a76 !important; }
28
+ .sl-dot-ok { background: #5cc28f !important; }
29
+ .sl-dot-alarm { background: #ff5a47 !important; }
30
+ }`.trim();
2
31
  function escapeHtml(value) {
3
32
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
4
33
  }
34
+ var TONE_COLOR = {
35
+ neutral: LIGHT.sub,
36
+ ok: LIGHT.ok,
37
+ alarm: LIGHT.alarm
38
+ };
39
+ var DOT_COLOR = {
40
+ neutral: LIGHT.faint,
41
+ ok: LIGHT.ok,
42
+ alarm: LIGHT.alarm
43
+ };
44
+ var TONE_CLASS = {
45
+ neutral: "sl-sub",
46
+ ok: "sl-ok",
47
+ alarm: "sl-alarm"
48
+ };
49
+ function dot(tone) {
50
+ return `<span class="sl-dot-${tone}" style="display: inline-block; width: 7px; height: 7px; border-radius: 999px; background: ${DOT_COLOR[tone]}; margin-right: 6px; vertical-align: 1px;"></span>`;
51
+ }
52
+ function statusChip(status) {
53
+ return `<span class="sl-line ${TONE_CLASS[status.tone]}" style="display: inline-block; border: 1px solid ${LIGHT.line}; border-radius: 999px; padding: 2px 8px; font-family: ${MONO}; font-size: 12px; line-height: 16px; color: ${TONE_COLOR[status.tone]}; white-space: nowrap;">${dot(status.tone)}${escapeHtml(status.text)}</span>`;
54
+ }
55
+ function preheaderHtml(preheader) {
56
+ if (!preheader)
57
+ return "";
58
+ const filler = "&#847;&zwnj;&nbsp;".repeat(60);
59
+ return `<div style="display: none; max-height: 0; overflow: hidden; mso-hide: all; opacity: 0; color: transparent;">${escapeHtml(preheader)}${filler}</div>`;
60
+ }
61
+ function figureHtml(input) {
62
+ if (!input.code && !input.facts?.length)
63
+ return "";
64
+ const title = input.figure ?? (input.code ? "sign-in code" : "details");
65
+ const line = `border-color: ${LIGHT.line}; border-style: solid; border-width: 0`;
66
+ const bar = `<tr>
67
+ <td class="sl-faint sl-line" style="padding: 8px 14px; ${line}; border-bottom-width: 1px; font-family: ${MONO}; font-size: 12px; line-height: 18px; color: ${LIGHT.faint};">${escapeHtml(title)}</td>
68
+ <td class="sl-line" align="right" style="padding: 8px 14px; ${line}; border-bottom-width: 1px;">${input.status ? statusChip(input.status) : ""}</td>
69
+ </tr>`;
70
+ let body;
71
+ if (input.code) {
72
+ body = `<tr><td colspan="2" align="center" class="sl-ink" style="padding: 24px 14px 8px; font-family: ${MONO}; font-size: 36px; line-height: 40px; font-weight: 500; letter-spacing: 0.3em; color: ${LIGHT.ink}; -webkit-user-select: all; user-select: all;">${escapeHtml(input.code)}</td></tr>
73
+ <tr><td colspan="2" align="center" class="sl-faint" style="padding: 0 14px 16px; font-family: ${MONO}; font-size: 12px; line-height: 18px; color: ${LIGHT.faint};">tap or double-click to select</td></tr>`;
74
+ } else {
75
+ const facts = input.facts ?? [];
76
+ body = facts.map((fact, i) => {
77
+ const top = i === 0 ? 12 : 2;
78
+ const bottom = i === facts.length - 1 ? 12 : 2;
79
+ const cell = `padding: ${top}px 14px ${bottom}px; font-family: ${MONO}; font-size: 13px; line-height: 20px; vertical-align: top;`;
80
+ return `<tr>
81
+ <td class="sl-faint" style="${cell} padding-right: 24px; width: 1%; color: ${LIGHT.faint}; white-space: nowrap;">${escapeHtml(fact.label.toLowerCase())}</td>
82
+ <td class="sl-ink" style="${cell} color: ${LIGHT.ink}; word-break: break-word;">${escapeHtml(fact.value)}</td>
83
+ </tr>`;
84
+ }).join(`
85
+ `);
86
+ }
87
+ return `<table role="presentation" cellpadding="0" cellspacing="0" class="sl-line" style="width: 100%; border: 1px solid ${LIGHT.line}; border-radius: 8px; border-collapse: separate; border-spacing: 0; margin: 8px 0 24px;">
88
+ ${bar}
89
+ ${body}
90
+ </table>`;
91
+ }
5
92
  function renderHtml(input) {
6
- const paragraphsHtml = input.paragraphs.map((p) => `<p style="color: #555; font-size: 14px; line-height: 1.6; margin: 0 0 16px;">${escapeHtml(p)}</p>`).join(`
7
- `);
8
- const codeHtml = input.code ? `<div style="background: #f5f5f5; border: 1px solid #e5e5e5; border-radius: 8px; padding: 20px; text-align: center; margin: 0 0 24px;">
9
- <span style="font-size: 32px; font-weight: 600; letter-spacing: 8px; color: #111;">${escapeHtml(input.code)}</span>
10
- </div>` : "";
11
- const factsHtml = input.facts?.length ? `<table role="presentation" cellpadding="0" cellspacing="0" style="width: 100%; margin: 0 0 24px; border-collapse: collapse;">
12
- ${input.facts.map((fact) => `<tr><td style="padding: 6px 0; color: #888; font-size: 13px;">${escapeHtml(fact.label)}</td><td style="padding: 6px 0; color: #111; font-size: 13px; text-align: right; font-weight: 600;">${escapeHtml(fact.value)}</td></tr>`).join(`
13
- `)}
14
- </table>` : "";
15
- const ctaHtml = input.cta ? `<a href="${escapeHtml(input.cta.url)}" style="display: inline-block; background: #111; color: #fff; text-decoration: none; padding: 10px 20px; border-radius: 6px; font-size: 14px; margin: 0 0 24px;">${escapeHtml(input.cta.label)}</a>` : "";
16
- const footnoteHtml = input.footnote ? `<p style="color: #aaa; font-size: 12px; margin: 24px 0 0;">${escapeHtml(input.footnote)}</p>` : "";
17
- return `
18
- <table role="presentation" cellpadding="0" cellspacing="0" style="width: 100%; background: #fff;">
93
+ const hasFigure = Boolean(input.code || input.facts?.length);
94
+ const statusLine = input.status && !hasFigure ? `<p class="${TONE_CLASS[input.status.tone]}" style="margin: 0 0 12px; font-size: 13px; line-height: 20px; color: ${TONE_COLOR[input.status.tone]};">${dot(input.status.tone)}${escapeHtml(input.status.text)}</p>` : "";
95
+ const paragraphsHtml = input.paragraphs.map((p) => `<p class="sl-sub" style="margin: 0 0 14px; font-size: 15px; line-height: 24px; color: ${LIGHT.sub};">${escapeHtml(p)}</p>`).join(`
96
+ `);
97
+ const quoteHtml = input.quote ? `<p class="sl-ink" style="margin: 0 0 14px; font-size: 15px; line-height: 24px; color: ${LIGHT.ink};">&ldquo;${escapeHtml(input.quote)}&rdquo;</p>` : "";
98
+ const ctaHtml = input.cta ? `<table role="presentation" cellpadding="0" cellspacing="0" style="margin: 10px 0 0;"><tr><td class="sl-pri" style="background: ${LIGHT.pri}; border-radius: 4px;"><a href="${escapeHtml(input.cta.url)}" style="display: inline-block; padding: 0 18px; height: 42px; line-height: 42px; font-family: ${SANS}; font-size: 15px; font-weight: 500; color: ${LIGHT.onPri}; text-decoration: none;">${escapeHtml(input.cta.label)}</a></td></tr></table>` : "";
99
+ const footnoteHtml = input.footnote ? `<p class="sl-faint" style="margin: 0 0 6px;">${escapeHtml(input.footnote)}</p>` : "";
100
+ return `<!doctype html>
101
+ <html lang="en">
102
+ <head>
103
+ <meta charset="utf-8">
104
+ <meta name="viewport" content="width=device-width, initial-scale=1">
105
+ <meta name="color-scheme" content="light dark">
106
+ <meta name="supported-color-schemes" content="light dark">
107
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500&family=Geist+Mono:wght@400;500&display=swap">
108
+ <style>
109
+ ${DARK_STYLE}
110
+ </style>
111
+ </head>
112
+ <body class="sl-paper" style="margin: 0; padding: 0; background: ${LIGHT.paper};">
113
+ ${preheaderHtml(input.preheader)}
114
+ <table role="presentation" cellpadding="0" cellspacing="0" class="sl-paper" style="width: 100%; background: ${LIGHT.paper};">
19
115
  <tr>
20
116
  <td align="center">
21
- <table role="presentation" cellpadding="0" cellspacing="0" style="width: 100%; max-width: 560px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; padding: 40px 20px;">
117
+ <table role="presentation" cellpadding="0" cellspacing="0" style="width: 100%; max-width: 560px; font-family: ${SANS}; padding: 40px 20px;">
22
118
  <tr>
23
119
  <td>
24
- <p style="color: #888; font-size: 14px; margin: 0 0 24px;">secondlayer</p>
25
- <p style="color: #111; font-size: 18px; font-weight: 600; margin: 0 0 16px;">${escapeHtml(input.heading)}</p>
120
+ <table role="presentation" cellpadding="0" cellspacing="0" style="margin: 0 0 32px;"><tr>
121
+ <td style="padding-right: 8px; vertical-align: middle;"><img src="${LOGO_URL}" width="30" height="20" alt="" style="display: block; border: 0;"></td>
122
+ <td class="sl-ink" style="vertical-align: middle; font-size: 15px; font-weight: 500; letter-spacing: -0.01em; color: ${LIGHT.ink};">secondlayer</td>
123
+ </tr></table>
124
+ ${statusLine}
125
+ <h1 class="sl-ink" style="margin: 0 0 14px; font-size: 24px; line-height: 29px; font-weight: 500; letter-spacing: -0.025em; color: ${LIGHT.ink};">${escapeHtml(input.heading)}</h1>
26
126
  ${paragraphsHtml}
27
- ${codeHtml}
28
- ${factsHtml}
127
+ ${quoteHtml}
128
+ ${figureHtml(input)}
29
129
  ${ctaHtml}
30
- ${footnoteHtml}
130
+ <div class="sl-line sl-faint" style="margin: 32px 0 0; padding: 16px 0 0; border-top: 1px solid ${LIGHT.line}; font-size: 12px; line-height: 18px; color: ${LIGHT.faint};">
131
+ ${footnoteHtml}
132
+ <p class="sl-faint" style="margin: 0;"><span class="sl-sub" style="color: ${LIGHT.sub}; font-weight: 500;">Secondlayer</span> &middot; ${TAGLINE}</p>
133
+ </div>
31
134
  </td>
32
135
  </tr>
33
136
  </table>
34
137
  </td>
35
138
  </tr>
36
- </table>`.trim();
139
+ </table>
140
+ </body>
141
+ </html>`;
37
142
  }
38
143
  function renderText(input) {
39
144
  const lines = [input.heading, ""];
40
145
  for (const p of input.paragraphs)
41
146
  lines.push(p, "");
42
- if (input.code) {
147
+ if (input.quote)
148
+ lines.push(`"${input.quote}"`, "");
149
+ if (input.status)
150
+ lines.push(input.status.text, "");
151
+ if (input.code)
43
152
  lines.push(`Code: ${input.code}`, "");
44
- }
45
153
  if (input.facts?.length) {
46
154
  for (const fact of input.facts)
47
155
  lines.push(`${fact.label}: ${fact.value}`);
48
156
  lines.push("");
49
157
  }
50
- if (input.cta) {
158
+ if (input.cta)
51
159
  lines.push(`${input.cta.label}: ${input.cta.url}`, "");
52
- }
53
- if (input.footnote) {
160
+ lines.push("--");
161
+ if (input.footnote)
54
162
  lines.push(input.footnote);
55
- }
56
- while (lines.length && lines[lines.length - 1] === "")
57
- lines.pop();
163
+ lines.push(`Secondlayer · ${TAGLINE}`);
58
164
  return lines.join(`
59
165
  `);
60
166
  }
@@ -227,5 +333,5 @@ export {
227
333
  sendEmail
228
334
  };
229
335
 
230
- //# debugId=33BAE8397C503C5864756E2164756E21
336
+ //# debugId=36F0F48E4EBB77FF64756E2164756E21
231
337
  //# sourceMappingURL=index.js.map
@@ -2,12 +2,12 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/email/render.ts", "../src/env.ts", "../src/logger.ts", "../src/email/send.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * The one HTML/text layout every customer email renders through. Table-based\n * HTML, inline styles only (email clients strip <style>), 560px max width,\n * white background, #111 text, one black button — same look as the login\n * email this was lifted from. Text is the same content, plainer.\n */\n\nexport interface FactRow {\n\tlabel: string;\n\tvalue: string;\n}\n\nexport interface EmailCta {\n\tlabel: string;\n\turl: string;\n}\n\nexport interface RenderEmailInput {\n\theading: string;\n\tparagraphs: string[];\n\t/** A code shown in a large, letter-spaced box (login codes). */\n\tcode?: string;\n\tfacts?: FactRow[];\n\tcta?: EmailCta;\n\tfootnote?: string;\n}\n\nexport interface RenderedEmail {\n\thtml: string;\n\ttext: string;\n}\n\nfunction escapeHtml(value: string): string {\n\treturn value\n\t\t.replace(/&/g, \"&amp;\")\n\t\t.replace(/</g, \"&lt;\")\n\t\t.replace(/>/g, \"&gt;\")\n\t\t.replace(/\"/g, \"&quot;\")\n\t\t.replace(/'/g, \"&#39;\");\n}\n\nfunction renderHtml(input: RenderEmailInput): string {\n\tconst paragraphsHtml = input.paragraphs\n\t\t.map(\n\t\t\t(p) =>\n\t\t\t\t`<p style=\"color: #555; font-size: 14px; line-height: 1.6; margin: 0 0 16px;\">${escapeHtml(p)}</p>`,\n\t\t)\n\t\t.join(\"\\n \");\n\n\tconst codeHtml = input.code\n\t\t? `<div style=\"background: #f5f5f5; border: 1px solid #e5e5e5; border-radius: 8px; padding: 20px; text-align: center; margin: 0 0 24px;\">\n <span style=\"font-size: 32px; font-weight: 600; letter-spacing: 8px; color: #111;\">${escapeHtml(input.code)}</span>\n </div>`\n\t\t: \"\";\n\n\tconst factsHtml = input.facts?.length\n\t\t? `<table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" style=\"width: 100%; margin: 0 0 24px; border-collapse: collapse;\">\n ${input.facts\n\t\t\t.map(\n\t\t\t\t(fact) =>\n\t\t\t\t\t`<tr><td style=\"padding: 6px 0; color: #888; font-size: 13px;\">${escapeHtml(fact.label)}</td><td style=\"padding: 6px 0; color: #111; font-size: 13px; text-align: right; font-weight: 600;\">${escapeHtml(fact.value)}</td></tr>`,\n\t\t\t)\n\t\t\t.join(\"\\n \")}\n </table>`\n\t\t: \"\";\n\n\tconst ctaHtml = input.cta\n\t\t? `<a href=\"${escapeHtml(input.cta.url)}\" style=\"display: inline-block; background: #111; color: #fff; text-decoration: none; padding: 10px 20px; border-radius: 6px; font-size: 14px; margin: 0 0 24px;\">${escapeHtml(input.cta.label)}</a>`\n\t\t: \"\";\n\n\tconst footnoteHtml = input.footnote\n\t\t? `<p style=\"color: #aaa; font-size: 12px; margin: 24px 0 0;\">${escapeHtml(input.footnote)}</p>`\n\t\t: \"\";\n\n\treturn `\n<table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" style=\"width: 100%; background: #fff;\">\n <tr>\n <td align=\"center\">\n <table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" style=\"width: 100%; max-width: 560px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; padding: 40px 20px;\">\n <tr>\n <td>\n <p style=\"color: #888; font-size: 14px; margin: 0 0 24px;\">secondlayer</p>\n <p style=\"color: #111; font-size: 18px; font-weight: 600; margin: 0 0 16px;\">${escapeHtml(input.heading)}</p>\n ${paragraphsHtml}\n ${codeHtml}\n ${factsHtml}\n ${ctaHtml}\n ${footnoteHtml}\n </td>\n </tr>\n </table>\n </td>\n </tr>\n</table>`.trim();\n}\n\nfunction renderText(input: RenderEmailInput): string {\n\tconst lines: string[] = [input.heading, \"\"];\n\tfor (const p of input.paragraphs) lines.push(p, \"\");\n\tif (input.code) {\n\t\tlines.push(`Code: ${input.code}`, \"\");\n\t}\n\tif (input.facts?.length) {\n\t\tfor (const fact of input.facts) lines.push(`${fact.label}: ${fact.value}`);\n\t\tlines.push(\"\");\n\t}\n\tif (input.cta) {\n\t\tlines.push(`${input.cta.label}: ${input.cta.url}`, \"\");\n\t}\n\tif (input.footnote) {\n\t\tlines.push(input.footnote);\n\t}\n\t// Trim trailing blank lines.\n\twhile (lines.length && lines[lines.length - 1] === \"\") lines.pop();\n\treturn lines.join(\"\\n\");\n}\n\nexport function renderEmail(input: RenderEmailInput): RenderedEmail {\n\treturn { html: renderHtml(input), text: renderText(input) };\n}\n",
5
+ "/**\n * The one HTML/text layout every customer email renders through, in the\n * brand's \"Figure\" look: logo + wordmark, a 24px heading, muted prose, the\n * code or facts inside a hairline code figure whose bar names it and carries\n * a status chip, one blue button, and a hairline footer.\n *\n * Table-based HTML with inline styles (most clients strip <style>). The head\n * <style> only adds dark mode for clients that honor `prefers-color-scheme`\n * (Apple Mail, iOS); everyone else gets the light palette, which Gmail\n * inverts on its own. Geist loads where web fonts work, the system stack\n * elsewhere. Callers pass content; every color lives here.\n */\n\nexport interface FactRow {\n\tlabel: string;\n\tvalue: string;\n}\n\nexport interface EmailCta {\n\tlabel: string;\n\turl: string;\n}\n\n/** `alarm` only for failures and stops, `ok` only for success. */\nexport type EmailTone = \"neutral\" | \"ok\" | \"alarm\";\n\nexport interface EmailStatus {\n\ttone: EmailTone;\n\ttext: string;\n}\n\nexport interface RenderEmailInput {\n\theading: string;\n\t/** The inbox preview line after the subject. Not shown in the body. */\n\tpreheader?: string;\n\tparagraphs: string[];\n\t/** Someone else's words, quoted (a contact form message). */\n\tquote?: string;\n\t/** A sign-in code, shown as one selectable run of digits in the figure. */\n\tcode?: string;\n\tfacts?: FactRow[];\n\t/** The figure's title bar. Defaults to \"sign-in code\" or \"details\". */\n\tfigure?: string;\n\t/** A chip in the figure bar, or a status line when there is no figure. */\n\tstatus?: EmailStatus;\n\tcta?: EmailCta;\n\t/** Why the reader got this email and how to stop it. */\n\tfootnote?: string;\n}\n\nexport interface RenderedEmail {\n\thtml: string;\n\ttext: string;\n}\n\n// www directly: the apex 307s there, and every image fetch would pay for it.\nconst LOGO_URL = \"https://www.secondlayer.tools/email/logo.png\";\nconst TAGLINE = \"Instant data for apps on Bitcoin\";\n\nconst SANS =\n\t\"Geist, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif\";\nconst MONO =\n\t\"'Geist Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace\";\n\n// DESIGN.md roles. Light inline; dark via the head <style> classes below.\nconst LIGHT = {\n\tpaper: \"#fbfaf7\",\n\tink: \"#14110d\",\n\tsub: \"#63605c\",\n\tfaint: \"#9d9b97\",\n\tline: \"#e8e6e3\",\n\tpri: \"#1f45e0\",\n\tonPri: \"#fbfaf7\",\n\tok: \"#128a43\",\n\talarm: \"#e3301e\",\n};\n\nconst DARK_STYLE = `\n@media (prefers-color-scheme: dark) {\n .sl-paper { background: #1e1b17 !important; }\n .sl-ink { color: #e8e6e3 !important; }\n .sl-sub { color: #b3b1ad !important; }\n .sl-faint { color: #7c7a76 !important; }\n .sl-line { border-color: #393632 !important; }\n .sl-pri { background: #3a5bff !important; }\n .sl-ok { color: #5cc28f !important; }\n .sl-alarm { color: #ff5a47 !important; }\n .sl-dot-neutral { background: #7c7a76 !important; }\n .sl-dot-ok { background: #5cc28f !important; }\n .sl-dot-alarm { background: #ff5a47 !important; }\n}`.trim();\n\nfunction escapeHtml(value: string): string {\n\treturn value\n\t\t.replace(/&/g, \"&amp;\")\n\t\t.replace(/</g, \"&lt;\")\n\t\t.replace(/>/g, \"&gt;\")\n\t\t.replace(/\"/g, \"&quot;\")\n\t\t.replace(/'/g, \"&#39;\");\n}\n\nconst TONE_COLOR: Record<EmailTone, string> = {\n\tneutral: LIGHT.sub,\n\tok: LIGHT.ok,\n\talarm: LIGHT.alarm,\n};\nconst DOT_COLOR: Record<EmailTone, string> = {\n\tneutral: LIGHT.faint,\n\tok: LIGHT.ok,\n\talarm: LIGHT.alarm,\n};\nconst TONE_CLASS: Record<EmailTone, string> = {\n\tneutral: \"sl-sub\",\n\tok: \"sl-ok\",\n\talarm: \"sl-alarm\",\n};\n\nfunction dot(tone: EmailTone): string {\n\treturn `<span class=\"sl-dot-${tone}\" style=\"display: inline-block; width: 7px; height: 7px; border-radius: 999px; background: ${DOT_COLOR[tone]}; margin-right: 6px; vertical-align: 1px;\"></span>`;\n}\n\nfunction statusChip(status: EmailStatus): string {\n\treturn `<span class=\"sl-line ${TONE_CLASS[status.tone]}\" style=\"display: inline-block; border: 1px solid ${LIGHT.line}; border-radius: 999px; padding: 2px 8px; font-family: ${MONO}; font-size: 12px; line-height: 16px; color: ${TONE_COLOR[status.tone]}; white-space: nowrap;\">${dot(status.tone)}${escapeHtml(status.text)}</span>`;\n}\n\nfunction preheaderHtml(preheader: string | undefined): string {\n\tif (!preheader) return \"\";\n\t// Trailing joiners keep body text from leaking into the preview line.\n\tconst filler = \"&#847;&zwnj;&nbsp;\".repeat(60);\n\treturn `<div style=\"display: none; max-height: 0; overflow: hidden; mso-hide: all; opacity: 0; color: transparent;\">${escapeHtml(preheader)}${filler}</div>`;\n}\n\nfunction figureHtml(input: RenderEmailInput): string {\n\tif (!input.code && !input.facts?.length) return \"\";\n\tconst title = input.figure ?? (input.code ? \"sign-in code\" : \"details\");\n\tconst line = `border-color: ${LIGHT.line}; border-style: solid; border-width: 0`;\n\n\tconst bar = `<tr>\n <td class=\"sl-faint sl-line\" style=\"padding: 8px 14px; ${line}; border-bottom-width: 1px; font-family: ${MONO}; font-size: 12px; line-height: 18px; color: ${LIGHT.faint};\">${escapeHtml(title)}</td>\n <td class=\"sl-line\" align=\"right\" style=\"padding: 8px 14px; ${line}; border-bottom-width: 1px;\">${input.status ? statusChip(input.status) : \"\"}</td>\n </tr>`;\n\n\tlet body: string;\n\tif (input.code) {\n\t\tbody = `<tr><td colspan=\"2\" align=\"center\" class=\"sl-ink\" style=\"padding: 24px 14px 8px; font-family: ${MONO}; font-size: 36px; line-height: 40px; font-weight: 500; letter-spacing: 0.3em; color: ${LIGHT.ink}; -webkit-user-select: all; user-select: all;\">${escapeHtml(input.code)}</td></tr>\n <tr><td colspan=\"2\" align=\"center\" class=\"sl-faint\" style=\"padding: 0 14px 16px; font-family: ${MONO}; font-size: 12px; line-height: 18px; color: ${LIGHT.faint};\">tap or double-click to select</td></tr>`;\n\t} else {\n\t\tconst facts = input.facts ?? [];\n\t\tbody = facts\n\t\t\t.map((fact, i) => {\n\t\t\t\tconst top = i === 0 ? 12 : 2;\n\t\t\t\tconst bottom = i === facts.length - 1 ? 12 : 2;\n\t\t\t\tconst cell = `padding: ${top}px 14px ${bottom}px; font-family: ${MONO}; font-size: 13px; line-height: 20px; vertical-align: top;`;\n\t\t\t\treturn `<tr>\n <td class=\"sl-faint\" style=\"${cell} padding-right: 24px; width: 1%; color: ${LIGHT.faint}; white-space: nowrap;\">${escapeHtml(fact.label.toLowerCase())}</td>\n <td class=\"sl-ink\" style=\"${cell} color: ${LIGHT.ink}; word-break: break-word;\">${escapeHtml(fact.value)}</td>\n </tr>`;\n\t\t\t})\n\t\t\t.join(\"\\n \");\n\t}\n\n\treturn `<table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" class=\"sl-line\" style=\"width: 100%; border: 1px solid ${LIGHT.line}; border-radius: 8px; border-collapse: separate; border-spacing: 0; margin: 8px 0 24px;\">\n ${bar}\n ${body}\n </table>`;\n}\n\nfunction renderHtml(input: RenderEmailInput): string {\n\tconst hasFigure = Boolean(input.code || input.facts?.length);\n\n\tconst statusLine =\n\t\tinput.status && !hasFigure\n\t\t\t? `<p class=\"${TONE_CLASS[input.status.tone]}\" style=\"margin: 0 0 12px; font-size: 13px; line-height: 20px; color: ${TONE_COLOR[input.status.tone]};\">${dot(input.status.tone)}${escapeHtml(input.status.text)}</p>`\n\t\t\t: \"\";\n\n\tconst paragraphsHtml = input.paragraphs\n\t\t.map(\n\t\t\t(p) =>\n\t\t\t\t`<p class=\"sl-sub\" style=\"margin: 0 0 14px; font-size: 15px; line-height: 24px; color: ${LIGHT.sub};\">${escapeHtml(p)}</p>`,\n\t\t)\n\t\t.join(\"\\n \");\n\n\tconst quoteHtml = input.quote\n\t\t? `<p class=\"sl-ink\" style=\"margin: 0 0 14px; font-size: 15px; line-height: 24px; color: ${LIGHT.ink};\">&ldquo;${escapeHtml(input.quote)}&rdquo;</p>`\n\t\t: \"\";\n\n\tconst ctaHtml = input.cta\n\t\t? `<table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" style=\"margin: 10px 0 0;\"><tr><td class=\"sl-pri\" style=\"background: ${LIGHT.pri}; border-radius: 4px;\"><a href=\"${escapeHtml(input.cta.url)}\" style=\"display: inline-block; padding: 0 18px; height: 42px; line-height: 42px; font-family: ${SANS}; font-size: 15px; font-weight: 500; color: ${LIGHT.onPri}; text-decoration: none;\">${escapeHtml(input.cta.label)}</a></td></tr></table>`\n\t\t: \"\";\n\n\tconst footnoteHtml = input.footnote\n\t\t? `<p class=\"sl-faint\" style=\"margin: 0 0 6px;\">${escapeHtml(input.footnote)}</p>`\n\t\t: \"\";\n\n\treturn `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<meta name=\"color-scheme\" content=\"light dark\">\n<meta name=\"supported-color-schemes\" content=\"light dark\">\n<link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css2?family=Geist:wght@400;500&family=Geist+Mono:wght@400;500&display=swap\">\n<style>\n${DARK_STYLE}\n</style>\n</head>\n<body class=\"sl-paper\" style=\"margin: 0; padding: 0; background: ${LIGHT.paper};\">\n${preheaderHtml(input.preheader)}\n<table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" class=\"sl-paper\" style=\"width: 100%; background: ${LIGHT.paper};\">\n <tr>\n <td align=\"center\">\n <table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" style=\"width: 100%; max-width: 560px; font-family: ${SANS}; padding: 40px 20px;\">\n <tr>\n <td>\n <table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" style=\"margin: 0 0 32px;\"><tr>\n <td style=\"padding-right: 8px; vertical-align: middle;\"><img src=\"${LOGO_URL}\" width=\"30\" height=\"20\" alt=\"\" style=\"display: block; border: 0;\"></td>\n <td class=\"sl-ink\" style=\"vertical-align: middle; font-size: 15px; font-weight: 500; letter-spacing: -0.01em; color: ${LIGHT.ink};\">secondlayer</td>\n </tr></table>\n ${statusLine}\n <h1 class=\"sl-ink\" style=\"margin: 0 0 14px; font-size: 24px; line-height: 29px; font-weight: 500; letter-spacing: -0.025em; color: ${LIGHT.ink};\">${escapeHtml(input.heading)}</h1>\n ${paragraphsHtml}\n ${quoteHtml}\n ${figureHtml(input)}\n ${ctaHtml}\n <div class=\"sl-line sl-faint\" style=\"margin: 32px 0 0; padding: 16px 0 0; border-top: 1px solid ${LIGHT.line}; font-size: 12px; line-height: 18px; color: ${LIGHT.faint};\">\n ${footnoteHtml}\n <p class=\"sl-faint\" style=\"margin: 0;\"><span class=\"sl-sub\" style=\"color: ${LIGHT.sub}; font-weight: 500;\">Secondlayer</span> &middot; ${TAGLINE}</p>\n </div>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n</table>\n</body>\n</html>`;\n}\n\nfunction renderText(input: RenderEmailInput): string {\n\tconst lines: string[] = [input.heading, \"\"];\n\tfor (const p of input.paragraphs) lines.push(p, \"\");\n\tif (input.quote) lines.push(`\"${input.quote}\"`, \"\");\n\tif (input.status) lines.push(input.status.text, \"\");\n\tif (input.code) lines.push(`Code: ${input.code}`, \"\");\n\tif (input.facts?.length) {\n\t\tfor (const fact of input.facts) lines.push(`${fact.label}: ${fact.value}`);\n\t\tlines.push(\"\");\n\t}\n\tif (input.cta) lines.push(`${input.cta.label}: ${input.cta.url}`, \"\");\n\tlines.push(\"--\");\n\tif (input.footnote) lines.push(input.footnote);\n\tlines.push(`Secondlayer · ${TAGLINE}`);\n\treturn lines.join(\"\\n\");\n}\n\nexport function renderEmail(input: RenderEmailInput): RenderedEmail {\n\treturn { html: renderHtml(input), text: renderText(input) };\n}\n",
6
6
  "import { z } from \"zod\";\n\n// Parse comma-separated networks\nconst networksSchema = z.string().transform((val) => {\n\tconst networks = val\n\t\t.split(\",\")\n\t\t.map((n) => n.trim())\n\t\t.filter(Boolean);\n\tconst valid = [\"mainnet\", \"testnet\"];\n\tfor (const n of networks) {\n\t\tif (!valid.includes(n)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid network: ${n}. Must be one of: ${valid.join(\", \")}`,\n\t\t\t);\n\t\t}\n\t}\n\treturn networks as (\"mainnet\" | \"testnet\")[];\n});\n\ninterface EnvSchemaOutput {\n\tDATABASE_URL?: string;\n\t/**\n\t * Shared indexer DB (blocks/txs/events). Falls back to DATABASE_URL.\n\t * Set this alongside TARGET_DATABASE_URL to enable dual-DB mode.\n\t */\n\tSOURCE_DATABASE_URL?: string;\n\t/**\n\t * Tenant DB (subgraph schemas + subgraphs table). Falls back to DATABASE_URL.\n\t * Set this alongside SOURCE_DATABASE_URL to enable dual-DB mode.\n\t */\n\tTARGET_DATABASE_URL?: string;\n\tNETWORK?: \"mainnet\" | \"testnet\";\n\tNETWORKS?: (\"mainnet\" | \"testnet\")[];\n\tLOG_LEVEL: \"debug\" | \"info\" | \"warn\" | \"error\";\n\tNODE_ENV: \"development\" | \"production\" | \"test\";\n}\n\n// Cast needed: z.preprocess / z.default create different _input vs _output types\n// that z.ZodType<T> can't represent without explicit input type param\nconst envSchema: z.ZodType<EnvSchemaOutput> = z.object({\n\tDATABASE_URL: z.preprocess(\n\t\t(val) => (typeof val === \"string\" && val.length === 0 ? undefined : val),\n\t\tz.string().url().optional(),\n\t),\n\tSOURCE_DATABASE_URL: z.preprocess(\n\t\t(val) => (typeof val === \"string\" && val.length === 0 ? undefined : val),\n\t\tz.string().url().optional(),\n\t),\n\tTARGET_DATABASE_URL: z.preprocess(\n\t\t(val) => (typeof val === \"string\" && val.length === 0 ? undefined : val),\n\t\tz.string().url().optional(),\n\t),\n\tNETWORK: z.enum([\"mainnet\", \"testnet\"]).optional(),\n\tNETWORKS: networksSchema.optional(),\n\tLOG_LEVEL: z.enum([\"debug\", \"info\", \"warn\", \"error\"]).default(\"info\"),\n\tNODE_ENV: z\n\t\t.enum([\"development\", \"production\", \"test\"])\n\t\t.default(\"development\"),\n}) as unknown as z.ZodType<EnvSchemaOutput>;\n\nexport type Env = EnvSchemaOutput & {\n\tenabledNetworks: (\"mainnet\" | \"testnet\")[];\n};\n\nlet cachedEnv: Env | null = null;\n\nexport function getEnv(): Env {\n\tif (cachedEnv) {\n\t\treturn cachedEnv;\n\t}\n\n\tconst result = envSchema.safeParse(process.env);\n\n\tif (!result.success) {\n\t\tconsole.error(\"❌ Invalid environment configuration:\");\n\t\tconsole.error(z.treeifyError(result.error));\n\t\tthrow new Error(\"Invalid environment configuration\");\n\t}\n\n\t// Compute enabled networks from NETWORKS or NETWORK\n\tlet enabledNetworks: (\"mainnet\" | \"testnet\")[];\n\tif (result.data.NETWORKS && result.data.NETWORKS.length > 0) {\n\t\tenabledNetworks = result.data.NETWORKS;\n\t} else if (result.data.NETWORK) {\n\t\tenabledNetworks = [result.data.NETWORK];\n\t} else {\n\t\tenabledNetworks = [\"mainnet\"]; // Default\n\t}\n\n\tcachedEnv = { ...result.data, enabledNetworks };\n\treturn cachedEnv;\n}\n\n/**\n * True when `NODE_ENV=production`, read at RUNTIME — the single source of truth\n * for prod-vs-dev branching in this package.\n *\n * Why a helper instead of inlining `process.env.NODE_ENV === \"production\"`:\n * bunup/esbuild constant-folds the dot-access `process.env.NODE_ENV` to its\n * BUILD-time value. `@secondlayer/shared` is consumed by other services as its\n * built `dist`, so an inlined check freezes to a literal in the shipped bundle\n * (e.g. `const isProd = false`) and silently ignores the container's real\n * NODE_ENV. The bracket access below is NOT folded, so it stays a runtime read.\n * Route every prod check through here so the footgun lives in exactly one place.\n */\nexport function isProductionEnv(): boolean {\n\t// biome-ignore lint/complexity/useLiteralKeys: bracket access is deliberate — dot-access gets constant-folded by the bundler, freezing this to a build-time literal in the shipped dist.\n\treturn process.env[\"NODE_ENV\"] === \"production\";\n}\n\ntype EnvMap = NodeJS.ProcessEnv;\n\n/**\n * PoX-4 stacking decoder is ON by default — `/v1/index/stacking` is part of the\n * public surface, so the decoder that fills `pox4_calls` runs unless explicitly\n * opted out with `POX4_DECODER_ENABLED=false` (mirrors the sBTC decoder policy).\n */\nexport function isPox4DecoderEnabled(env: EnvMap = process.env): boolean {\n\treturn env.POX4_DECODER_ENABLED !== \"false\";\n}\n\n/**\n * PoX-5 print-event decoder is ON by default (mirrors pox-4/sBTC policy).\n * No activation gating needed: pox-5 events cannot exist before the Epoch 4.0\n * hard fork (Bitcoin block 960,230), so pre-activation the decoder idles at\n * tip. Opt out with `POX5_DECODER_ENABLED=false`.\n */\nexport function isPox5DecoderEnabled(env: EnvMap = process.env): boolean {\n\treturn env.POX5_DECODER_ENABLED !== \"false\";\n}\n\n/** Default ON. Opt out with `SBTC_DECODER_ENABLED=false`. */\nexport function isSbtcDecoderEnabled(env: EnvMap = process.env): boolean {\n\treturn env.SBTC_DECODER_ENABLED !== \"false\";\n}\n\n/** Default OFF. Opt in with `BNS_DECODER_ENABLED=true`. */\nexport function isBnsDecoderEnabled(env: EnvMap = process.env): boolean {\n\treturn env.BNS_DECODER_ENABLED === \"true\";\n}\n\n// Export for testing\nexport { envSchema };\n",
7
7
  "import { getEnv } from \"./env.ts\";\n\ntype LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n\tdebug: 0,\n\tinfo: 1,\n\twarn: 2,\n\terror: 3,\n};\n\nclass Logger {\n\tprivate _level?: LogLevel;\n\tprivate _isProduction?: boolean;\n\tprivate _initialized = false;\n\n\tprivate init() {\n\t\tif (this._initialized) return;\n\t\tthis._initialized = true;\n\t\ttry {\n\t\t\tconst env = getEnv();\n\t\t\tthis._level = env.LOG_LEVEL;\n\t\t\tthis._isProduction = env.NODE_ENV === \"production\";\n\t\t} catch {\n\t\t\t// Fallback when env is unavailable (e.g. tests without DATABASE_URL)\n\t\t\tthis._level = \"info\";\n\t\t\tthis._isProduction = false;\n\t\t}\n\t}\n\n\tprivate get level(): LogLevel {\n\t\tthis.init();\n\t\t// biome-ignore lint/style/noNonNullAssertion: value is non-null after preceding check or by construction; TS narrowing limitation\n\t\treturn this._level!;\n\t}\n\n\tprivate get isProduction(): boolean {\n\t\tthis.init();\n\t\t// biome-ignore lint/style/noNonNullAssertion: value is non-null after preceding check or by construction; TS narrowing limitation\n\t\treturn this._isProduction!;\n\t}\n\n\tprivate shouldLog(level: LogLevel): boolean {\n\t\treturn LOG_LEVELS[level] >= LOG_LEVELS[this.level];\n\t}\n\n\tprivate formatMessage(\n\t\tlevel: LogLevel,\n\t\tmessage: string,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: interop boundary or dynamic-shape value where typing adds friction without runtime safety\n\t\tmeta?: Record<string, any>,\n\t) {\n\t\tconst timestamp = new Date().toISOString();\n\n\t\tif (this.isProduction) {\n\t\t\t// JSON output for production\n\t\t\treturn JSON.stringify({\n\t\t\t\ttimestamp,\n\t\t\t\tlevel,\n\t\t\t\tmessage,\n\t\t\t\t...meta,\n\t\t\t});\n\t\t}\n\n\t\t// Human-readable output for development\n\t\tconst metaStr = meta ? ` ${JSON.stringify(meta)}` : \"\";\n\t\treturn `[${timestamp}] ${level.toUpperCase()}: ${message}${metaStr}`;\n\t}\n\n\t// biome-ignore lint/suspicious/noExplicitAny: interop boundary or dynamic-shape value where typing adds friction without runtime safety\n\tdebug(message: string, meta?: Record<string, any>): void {\n\t\tif (this.shouldLog(\"debug\")) {\n\t\t\tconsole.debug(this.formatMessage(\"debug\", message, meta));\n\t\t}\n\t}\n\n\t// biome-ignore lint/suspicious/noExplicitAny: interop boundary or dynamic-shape value where typing adds friction without runtime safety\n\tinfo(message: string, meta?: Record<string, any>): void {\n\t\tif (this.shouldLog(\"info\")) {\n\t\t\tconsole.info(this.formatMessage(\"info\", message, meta));\n\t\t}\n\t}\n\n\t// biome-ignore lint/suspicious/noExplicitAny: interop boundary or dynamic-shape value where typing adds friction without runtime safety\n\twarn(message: string, meta?: Record<string, any>): void {\n\t\tif (this.shouldLog(\"warn\")) {\n\t\t\tconsole.warn(this.formatMessage(\"warn\", message, meta));\n\t\t}\n\t}\n\n\t// biome-ignore lint/suspicious/noExplicitAny: interop boundary or dynamic-shape value where typing adds friction without runtime safety\n\terror(message: string, meta?: Record<string, any>): void {\n\t\tif (this.shouldLog(\"error\")) {\n\t\t\tconsole.error(this.formatMessage(\"error\", message, meta));\n\t\t}\n\t}\n}\n\n// Export singleton instance\nexport const logger: Logger = new Logger();\n",
8
8
  "import { logger } from \"../logger.ts\";\n\n/**\n * The one Resend call every customer email goes through. Never throws when\n * `RESEND_API_KEY` is unset — that's a dev/CI/self-host state, not a send\n * failure — it logs a warning and reports `{ skipped: true }` so a caller\n * can still record its own \"notification sent\" bookkeeping accurately.\n */\n\nexport interface SendEmailInput {\n\tto: string;\n\tsubject: string;\n\thtml: string;\n\ttext: string;\n\t/** Where a reply goes; omitted, replies go to the From address. */\n\treplyTo?: string;\n}\n\nexport type SendEmailResult = { skipped: true } | { skipped: false };\n\nexport async function sendEmail(\n\tinput: SendEmailInput,\n): Promise<SendEmailResult> {\n\tconst apiKey = process.env.RESEND_API_KEY;\n\tif (!apiKey) {\n\t\tlogger.warn(\"RESEND_API_KEY unset — skipping email\", {\n\t\t\tsubject: input.subject,\n\t\t});\n\t\treturn { skipped: true };\n\t}\n\n\tconst from =\n\t\tprocess.env.EMAIL_FROM ?? \"secondlayer <noreply@secondlayer.tools>\";\n\n\tconst response = await fetch(\"https://api.resend.com/emails\", {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\tAuthorization: `Bearer ${apiKey}`,\n\t\t},\n\t\tbody: JSON.stringify({\n\t\t\tfrom,\n\t\t\tto: [input.to],\n\t\t\tsubject: input.subject,\n\t\t\thtml: input.html,\n\t\t\ttext: input.text,\n\t\t\t...(input.replyTo ? { reply_to: [input.replyTo] } : {}),\n\t\t}),\n\t});\n\n\tif (!response.ok) {\n\t\tconst body = await response.text().catch(() => \"\");\n\t\tthrow new Error(\n\t\t\t`Resend API error (${response.status}): ${body.slice(0, 200)}`,\n\t\t);\n\t}\n\n\treturn { skipped: false };\n}\n"
9
9
  ],
10
- "mappings": "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",
11
- "debugId": "33BAE8397C503C5864756E2164756E21",
10
+ "mappings": "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",
11
+ "debugId": "36F0F48E4EBB77FF64756E2164756E21",
12
12
  "names": []
13
13
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@secondlayer/shared",
3
- "version": "13.13.0",
3
+ "version": "13.13.1",
4
4
  "description": "Internal building blocks shared across Secondlayer packages.",
5
5
  "license": "MIT",
6
6
  "repository": {