@sevenfold/setto-client 0.34.0 → 0.35.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.
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ export type { SettoIconProps, SettoIconRenderProps } from './SettoIcon';
13
13
  export { SettoImage } from './SettoImage';
14
14
  export type { SettoImageProps, ImageToolsProps } from './SettoImage';
15
15
  export { SETTO_IMAGE_QUALITY, SETTO_IMAGE_WIDTHS, isOptimizable, optimizedSrcSet, optimizedUrl, settoVercelImagesConfig, } from './lib/optimized-image';
16
+ export { SETTO_MEDIA_HOST, isSettoMediaUrl } from './lib/media';
16
17
  export { SettoRepeater } from './SettoRepeater';
17
18
  export type { SettoRepeaterProps } from './SettoRepeater';
18
19
  export { SettoForm, FORM_FIELD_TYPES, FORM_FIELD_TYPE_LABELS, fieldTypeHasOptions, fieldTypeHasPlaceholder, formFieldsPrefix, isFormFieldType, readLocaleFields, settoSubmissionUrl, } from './modules/forms';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Setto's public media store: the `setto-media` Vercel Blob store, where blog
3
+ * photographs live instead of in each site's repo (R24). setto-server writes
4
+ * to it (`blog/<siteId>/<hash>/<name>.<ext>`), a post refers to the URL, and
5
+ * the site's Vercel Image Optimization resizes it through the
6
+ * `remotePatterns` entry in `settoVercelImagesConfig`.
7
+ *
8
+ * One store for every site, so its host is a constant. It changes only if the
9
+ * store is replaced — then here, in the server's token, and in each site's
10
+ * `vercel.json`, together.
11
+ */
12
+ export declare const SETTO_MEDIA_HOST = "3adyw42hy72dtzjo.public.blob.vercel-storage.com";
13
+ /** Where blog photographs sit in the store. */
14
+ export declare const SETTO_MEDIA_BLOG_PREFIX = "/blog/";
15
+ /** A blog photograph in Setto's media store: https, that host, under `/blog/`. */
16
+ export declare function isSettoMediaUrl(src: string | null | undefined): src is string;
@@ -8,6 +8,12 @@
8
8
  * `images` block in `vercel.json` whose `sizes` and `qualities` are exactly
9
9
  * the constants below — Vercel refuses a `w` or `q` it was not given. The
10
10
  * block, for copying: `settoVercelImagesConfig`.
11
+ *
12
+ * Blog photographs are the one exception to "a file of this site's own": they
13
+ * live in Setto's media store (`./media.ts`) and reach the optimizer through
14
+ * the block's `remotePatterns` entry. A site whose `vercel.json` predates that
15
+ * entry gets a refusal from the optimizer, and `SettoImage` falls back to the
16
+ * original, as it does for any failed variant.
11
17
  */
12
18
  /** Phone, phone at 2–3×, tablet, laptop, wide and retina desktop. */
13
19
  export declare const SETTO_IMAGE_WIDTHS: readonly [384, 640, 828, 1080, 1440, 1920, 2560];
@@ -22,12 +28,18 @@ export declare const settoVercelImagesConfig: {
22
28
  readonly pathname: "^/images/.*$";
23
29
  readonly search: "";
24
30
  }];
31
+ readonly remotePatterns: readonly [{
32
+ readonly protocol: "https";
33
+ readonly hostname: `^${string}$`;
34
+ readonly pathname: `^${string}.*$`;
35
+ }];
25
36
  readonly minimumCacheTTL: 2678400;
26
37
  };
27
38
  /**
28
39
  * Whether an image can go through the optimizer: a file of this site's own,
29
- * under `/images/`, in a format it transforms. A draft's `blob:` preview, an
30
- * external address, an SVG logo and a moving GIF cannot.
40
+ * under `/images/`, or a blog photograph in Setto's media store, in a format
41
+ * it transforms. A draft's `blob:` preview, any other external address, an
42
+ * SVG logo and a moving GIF cannot.
31
43
  */
32
44
  export declare function isOptimizable(src: string | null | undefined): src is string;
33
45
  /**
@@ -37714,6 +37714,18 @@ function SettoIcon({ k, icons, size = 24, className, style }) {
37714
37714
  )
37715
37715
  ] });
37716
37716
  }
37717
+ const SETTO_MEDIA_HOST = "3adyw42hy72dtzjo.public.blob.vercel-storage.com";
37718
+ const SETTO_MEDIA_BLOG_PREFIX = "/blog/";
37719
+ function isSettoMediaUrl(src) {
37720
+ if (!src) return false;
37721
+ try {
37722
+ const url = new URL(src);
37723
+ return url.protocol === "https:" && url.hostname === SETTO_MEDIA_HOST && !url.username && !url.password && url.port === "" && url.pathname.startsWith(SETTO_MEDIA_BLOG_PREFIX);
37724
+ } catch {
37725
+ return false;
37726
+ }
37727
+ }
37728
+ const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
37717
37729
  const SETTO_IMAGE_WIDTHS = [384, 640, 828, 1080, 1440, 1920, 2560];
37718
37730
  const SETTO_IMAGE_QUALITY = 75;
37719
37731
  const settoVercelImagesConfig = {
@@ -37721,12 +37733,23 @@ const settoVercelImagesConfig = {
37721
37733
  qualities: [SETTO_IMAGE_QUALITY],
37722
37734
  formats: ["image/avif", "image/webp"],
37723
37735
  localPatterns: [{ pathname: "^/images/.*$", search: "" }],
37736
+ // Vercel reads hostname and pathname as regular expressions; anchored so a
37737
+ // look-alike host cannot borrow the optimizer. Checked on a deployment
37738
+ // (R24): this form resizes, an unlisted host or path is refused with 400.
37739
+ remotePatterns: [
37740
+ {
37741
+ protocol: "https",
37742
+ hostname: `^${escapeRegExp(SETTO_MEDIA_HOST)}$`,
37743
+ pathname: `^${escapeRegExp(SETTO_MEDIA_BLOG_PREFIX)}.*$`
37744
+ }
37745
+ ],
37724
37746
  minimumCacheTTL: 2678400
37725
37747
  };
37726
37748
  const OPTIMIZABLE = /\.(jpe?g|png|webp|avif)$/i;
37727
37749
  function isOptimizable(src) {
37728
- if (!src || !src.startsWith("/images/")) return false;
37729
- return OPTIMIZABLE.test(src.split(/[?#]/)[0]);
37750
+ if (!src) return false;
37751
+ if (src.startsWith("/images/")) return OPTIMIZABLE.test(src.split(/[?#]/)[0]);
37752
+ return isSettoMediaUrl(src) && OPTIMIZABLE.test(new URL(src).pathname);
37730
37753
  }
37731
37754
  function hasNoOptimizer(hostname) {
37732
37755
  return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]" || hostname.endsWith(".localhost");
@@ -40280,6 +40303,7 @@ export {
40280
40303
  SETTO_BASE,
40281
40304
  SETTO_IMAGE_QUALITY,
40282
40305
  SETTO_IMAGE_WIDTHS,
40306
+ SETTO_MEDIA_HOST,
40283
40307
  SETTO_MODULES,
40284
40308
  SettoAdminApp,
40285
40309
  SettoAnimation,
@@ -40322,6 +40346,7 @@ export {
40322
40346
  isLinkContext,
40323
40347
  isOptimizable,
40324
40348
  isSafeHref,
40349
+ isSettoMediaUrl,
40325
40350
  languageFromPath,
40326
40351
  languageName,
40327
40352
  nodeChildren,