next-image-transformer 0.2.2 → 0.2.4

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.
@@ -0,0 +1 @@
1
+ export { createImageTransformRouteHandler } from "./createImageTransformRouteHandler";
package/dist/server.js ADDED
@@ -0,0 +1,198 @@
1
+ import h from "node:path";
2
+ import { z as C, c as B } from "./index-C4FbrW_M.js";
3
+ import { createHash as U } from "node:crypto";
4
+ import m from "node:fs/promises";
5
+ import b from "sharp";
6
+ function j({
7
+ canonicalUrl: r
8
+ }) {
9
+ return U("sha256").update(r).digest("hex");
10
+ }
11
+ function P({
12
+ cacheKey: r,
13
+ cacheDir: n
14
+ }) {
15
+ const s = r.slice(0, 2), a = r.slice(2), e = h.join(n, s);
16
+ return {
17
+ dir: e,
18
+ bodyPath: h.join(e, `${a}.bin`),
19
+ metaPath: h.join(e, `${a}.json`)
20
+ };
21
+ }
22
+ async function q({
23
+ cacheKey: r,
24
+ cacheDir: n
25
+ }) {
26
+ const { bodyPath: s, metaPath: a } = P({ cacheKey: r, cacheDir: n });
27
+ try {
28
+ const [e, u] = await Promise.all([
29
+ m.readFile(s),
30
+ m.readFile(a, "utf8")
31
+ ]), o = (() => {
32
+ try {
33
+ const i = JSON.parse(u), t = C.object({
34
+ contentType: C.string()
35
+ }).loose().safeParse(i);
36
+ return t.success ? t.data : null;
37
+ } catch {
38
+ return null;
39
+ }
40
+ })();
41
+ return o ? { body: new Uint8Array(e), contentType: o.contentType } : null;
42
+ } catch (e) {
43
+ if (e instanceof Error && "code" in e && e.code === "ENOENT")
44
+ return null;
45
+ throw e;
46
+ }
47
+ }
48
+ function x(r, n, s, a, e, u, o, i, t) {
49
+ switch (arguments.length) {
50
+ case 1:
51
+ return r;
52
+ case 2:
53
+ return n(r);
54
+ case 3:
55
+ return s(n(r));
56
+ case 4:
57
+ return a(s(n(r)));
58
+ case 5:
59
+ return e(a(s(n(r))));
60
+ case 6:
61
+ return u(e(a(s(n(r)))));
62
+ case 7:
63
+ return o(u(e(a(s(n(r))))));
64
+ case 8:
65
+ return i(o(u(e(a(s(n(r)))))));
66
+ case 9:
67
+ return t(i(o(u(e(a(s(n(r))))))));
68
+ default: {
69
+ for (var c = arguments[0], f = 1; f < arguments.length; f++)
70
+ c = arguments[f](c);
71
+ return c;
72
+ }
73
+ }
74
+ }
75
+ async function A({
76
+ cacheKey: r,
77
+ body: n,
78
+ meta: s,
79
+ cacheDir: a
80
+ }) {
81
+ const { dir: e, bodyPath: u, metaPath: o } = P({
82
+ cacheKey: r,
83
+ cacheDir: a
84
+ });
85
+ await m.mkdir(e, { recursive: !0 });
86
+ const i = `${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`, t = `${u}.${i}.tmp`, c = `${o}.${i}.tmp`;
87
+ await Promise.all([
88
+ m.writeFile(t, n),
89
+ m.writeFile(c, JSON.stringify(s), "utf8")
90
+ ]), await Promise.all([
91
+ m.rename(t, u),
92
+ m.rename(c, o)
93
+ ]);
94
+ }
95
+ const O = ({
96
+ apiRouteUrl: r,
97
+ cacheDir: n = h.join(process.cwd(), ".transform-cache"),
98
+ cacheControl: s = "public, max-age=31536000, immutable",
99
+ allowedHosts: a
100
+ }) => {
101
+ const e = B({ apiRouteUrl: r }), u = (o) => {
102
+ if (!a) return !0;
103
+ const i = o.hostname.toLowerCase(), t = o.host.toLowerCase();
104
+ return a.some((c) => {
105
+ if (c instanceof RegExp)
106
+ return c.test(i) || c.test(t);
107
+ const f = c.toLowerCase();
108
+ return f.includes(":") ? t === f : i === f;
109
+ });
110
+ };
111
+ return async function(i) {
112
+ const { data: t, error: c } = e.safeDecode(i.url);
113
+ if (c)
114
+ return new Response("Bad Request", { status: 400 });
115
+ const f = e.encode(
116
+ // encode() accepts the decoded transform config shape; we only call this
117
+ // after decoding has succeeded.
118
+ t
119
+ ), y = t.q ?? 100, g = j({ canonicalUrl: f }), d = await q({ cacheKey: g, cacheDir: n });
120
+ if (d)
121
+ return new Response(d.body, {
122
+ headers: {
123
+ "Content-Type": d.contentType,
124
+ "Cache-Control": s
125
+ }
126
+ });
127
+ let l;
128
+ try {
129
+ l = new URL(t.source);
130
+ } catch {
131
+ return new Response("Bad Request", { status: 400 });
132
+ }
133
+ if (l.protocol !== "http:" && l.protocol !== "https:")
134
+ return new Response("Bad Request", { status: 400 });
135
+ if (l.username || l.password)
136
+ return new Response("Bad Request", { status: 400 });
137
+ if (!u(l))
138
+ return new Response("Forbidden", { status: 403 });
139
+ const w = await fetch(l);
140
+ if (!w.ok)
141
+ return new Response("Upstream fetch failed", { status: 502 });
142
+ const v = b(Buffer.from(await w.arrayBuffer())), R = await x(
143
+ v,
144
+ /**
145
+ * auto-orient: read's the image's EXIF data and rotates it to the correct
146
+ * orientation.
147
+ */
148
+ (p) => p.rotate(),
149
+ /**
150
+ * Resize
151
+ */
152
+ (p) => t.w || t.h ? p.resize({
153
+ width: t.w,
154
+ height: t.h,
155
+ fit: "inside",
156
+ withoutEnlargement: !0
157
+ }) : p,
158
+ /**
159
+ * Change format
160
+ */
161
+ (p) => {
162
+ switch (t.fmt) {
163
+ case "preserve":
164
+ return p;
165
+ case "avif":
166
+ return p.avif({ quality: y });
167
+ case "webp":
168
+ return p.webp({ quality: y });
169
+ default:
170
+ throw new Error(`Unreachable case: ${t.fmt}`);
171
+ }
172
+ }
173
+ ).toBuffer(), $ = new Uint8Array(R), T = (() => {
174
+ switch (t.fmt) {
175
+ case "preserve":
176
+ return w.headers.get("content-type") ?? "application/octet-stream";
177
+ case "avif":
178
+ return "image/avif";
179
+ case "webp":
180
+ return "image/webp";
181
+ }
182
+ })();
183
+ return await A({
184
+ cacheKey: g,
185
+ body: R,
186
+ meta: { contentType: T },
187
+ cacheDir: n
188
+ }), new Response($, {
189
+ headers: {
190
+ "Content-Type": T,
191
+ "Cache-Control": s
192
+ }
193
+ });
194
+ };
195
+ };
196
+ export {
197
+ O as createImageTransformRouteHandler
198
+ };
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "next-image-transformer",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "exports": {
7
7
  ".": {
8
8
  "types": "./dist/index.d.ts",
9
9
  "import": "./dist/index.js"
10
+ },
11
+ "./server": {
12
+ "types": "./dist/server.d.ts",
13
+ "import": "./dist/server.js"
10
14
  }
11
15
  },
12
16
  "type": "module",
@@ -25,16 +29,17 @@
25
29
  "@types/node": "24",
26
30
  "np": "^10.2.0",
27
31
  "prettier": "^3.7.4",
32
+ "sharp": "^0.34.5",
28
33
  "typescript": "^5.9.3",
29
34
  "vite": "^7.3.0"
30
35
  },
31
36
  "dependencies": {
32
37
  "fp-ts": "^2.16.11",
33
- "sharp": "^0.34.5",
34
38
  "zod": "^4.3.5"
35
39
  },
36
40
  "peerDependencies": {
37
- "next": ">=13.4 <17"
41
+ "next": ">=13.4 <17",
42
+ "sharp": "<1"
38
43
  },
39
44
  "scripts": {
40
45
  "build": "vite build && tsc",