@anthusai/papyrus 2.0.0-next.60 → 2.0.0-next.61

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.
@@ -17,6 +17,7 @@ const THEME_STYLE_KEYS = [
17
17
  ];
18
18
  const THEME_KEYS = [
19
19
  "accent", "text", "background", ...THEME_STYLE_KEYS, "logoUrl", "wordmarkImageUrl", "wordmarkAlt", "wordmarkWidth", "wordmarkHeight",
20
+ "footerWordmarkWidth",
20
21
  ];
21
22
  const KNOWN_KEYS = new Set([
22
23
  "name", "siteId", "siteOrigin", "basePath", "computeRoleArn", "sendingDomain", "fromAddress", "fromName", "instantAlerts", "theme", "lists",
@@ -140,6 +141,15 @@ function resolveTheme(raw) {
140
141
  else if (theme.wordmarkWidth !== undefined || theme.wordmarkHeight !== undefined) {
141
142
  fail("theme.wordmarkWidth and theme.wordmarkHeight need theme.wordmarkImageUrl");
142
143
  }
144
+ if (theme.footerWordmarkWidth !== undefined) {
145
+ if (theme.wordmarkImageUrl === undefined)
146
+ fail("theme.footerWordmarkWidth needs theme.wordmarkImageUrl");
147
+ const width = theme.footerWordmarkWidth;
148
+ if (typeof width !== "number" || !Number.isInteger(width) || width < 1 || width > 400) {
149
+ fail("theme.footerWordmarkWidth must be a whole number of pixels from 1 to 400");
150
+ }
151
+ resolved.footerWordmarkWidth = width;
152
+ }
143
153
  if (theme.wordmarkAlt !== undefined) {
144
154
  const alt = text(theme.wordmarkAlt, "theme.wordmarkAlt", 200);
145
155
  if (/[\u0000-\u001f\u007f]/.test(alt))
@@ -37,6 +37,8 @@ export type NewsletterTheme = {
37
37
  wordmarkAlt?: string;
38
38
  wordmarkWidth?: number;
39
39
  wordmarkHeight?: number;
40
+ /** Draws the footer's wordmark at this width in pixels (1 to 400), smaller than the header's; the height keeps the aspect ratio. */
41
+ footerWordmarkWidth?: number;
40
42
  labelFont?: string;
41
43
  };
42
44
 
@@ -46,6 +48,7 @@ const THEME_STYLE_KEYS = [
46
48
  ] as const;
47
49
  const THEME_KEYS = [
48
50
  "accent", "text", "background", ...THEME_STYLE_KEYS, "logoUrl", "wordmarkImageUrl", "wordmarkAlt", "wordmarkWidth", "wordmarkHeight",
51
+ "footerWordmarkWidth",
49
52
  ];
50
53
 
51
54
  export type NewsletterRule = { sections?: string[]; tags?: string[]; types?: string[] };
@@ -205,6 +208,14 @@ function resolveTheme(raw: unknown): NewsletterTheme {
205
208
  } else if (theme.wordmarkWidth !== undefined || theme.wordmarkHeight !== undefined) {
206
209
  fail("theme.wordmarkWidth and theme.wordmarkHeight need theme.wordmarkImageUrl");
207
210
  }
211
+ if (theme.footerWordmarkWidth !== undefined) {
212
+ if (theme.wordmarkImageUrl === undefined) fail("theme.footerWordmarkWidth needs theme.wordmarkImageUrl");
213
+ const width = theme.footerWordmarkWidth;
214
+ if (typeof width !== "number" || !Number.isInteger(width) || width < 1 || width > 400) {
215
+ fail("theme.footerWordmarkWidth must be a whole number of pixels from 1 to 400");
216
+ }
217
+ resolved.footerWordmarkWidth = width;
218
+ }
208
219
  if (theme.wordmarkAlt !== undefined) {
209
220
  const alt = text(theme.wordmarkAlt, "theme.wordmarkAlt", 200);
210
221
  if (/[\u0000-\u001f\u007f]/.test(alt)) fail("theme.wordmarkAlt must not contain control characters");
@@ -238,6 +238,14 @@ function call(options: NewsletterApiOptions, functionName: string, event: Newsle
238
238
  return (options.invoke ?? invokeNewsletterLambda)(functionName, event);
239
239
  }
240
240
 
241
+ /**
242
+ * Next answers HEAD by running the route's GET export, but leaves `request.method` as "HEAD". A check for `=== "GET"` therefore
243
+ * sends a mail scanner's HEAD down the POST path. Every read-only branch asks this instead, so HEAD redirects exactly like GET.
244
+ */
245
+ function isReadRequest(request: Pick<NextRequest, "method">): boolean {
246
+ return request.method === "GET" || request.method === "HEAD";
247
+ }
248
+
241
249
  function textResponse(body: string, status: number): NextResponse {
242
250
  return new NextResponse(body, { status, headers: { ...NO_STORE, "content-type": "text/plain; charset=utf-8" } });
243
251
  }
@@ -266,7 +274,7 @@ export async function handleNewsletterConfirm(request: NextRequest, options: New
266
274
  if (!plugin) return notFoundPage();
267
275
  const to = redirector(request, environment, plugin);
268
276
  if ("response" in to) return to.response;
269
- if (request.method === "GET") {
277
+ if (isReadRequest(request)) {
270
278
  const token = manageTokenFrom(request.nextUrl.searchParams.get("t"));
271
279
  return token ? to.go("confirm", { token }, 302) : to.go("expired", {}, 302);
272
280
  }
@@ -304,7 +312,7 @@ export async function handleNewsletterUnsubscribe(request: NextRequest, options:
304
312
  const to = redirector(request, environment, plugin);
305
313
  if ("response" in to) return to.response;
306
314
  const query = request.nextUrl.searchParams;
307
- if (request.method === "GET") {
315
+ if (isReadRequest(request)) {
308
316
  const token = manageTokenFrom(query.get("t"));
309
317
  const listId = listParameter(query.get("l"));
310
318
  return token ? to.go("unsubscribe", { token, ...(listId ? { list: listId } : {}) }, 302) : to.go("expired", {}, 302);
@@ -344,7 +352,7 @@ export async function handleNewsletterPreferences(request: NextRequest, options:
344
352
  if (!plugin) return notFoundPage();
345
353
  const to = redirector(request, environment, plugin);
346
354
  if ("response" in to) return to.response;
347
- if (request.method === "GET") {
355
+ if (isReadRequest(request)) {
348
356
  const token = manageTokenFrom(request.nextUrl.searchParams.get("t"));
349
357
  return token ? to.go("preferences", { token }, 302) : to.go("expired", {}, 302);
350
358
  }
package/package.json CHANGED
@@ -433,7 +433,7 @@
433
433
  "optional": true
434
434
  }
435
435
  },
436
- "version": "2.0.0-next.60",
436
+ "version": "2.0.0-next.61",
437
437
  "dependencies": {
438
438
  "@aws-amplify/adapter-nextjs": "^1.7.3",
439
439
  "@aws-crypto/sha256-js": "5.2.0",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.0.0-next.60",
2
+ "version": "2.0.0-next.61",
3
3
  "routes": [
4
4
  {
5
5
  "file": "app/%5F_preview/[[...path]]/route.ts",