@howells/stow-next 0.1.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/README.md +183 -0
- package/dist/chunk-DZDX7UVD.mjs +39 -0
- package/dist/chunk-HRAABMBJ.mjs +87 -0
- package/dist/chunk-HYKV6KDZ.mjs +31 -0
- package/dist/chunk-WN3NWAEN.mjs +93 -0
- package/dist/chunk-WWNT32U5.mjs +62 -0
- package/dist/chunk-X2Y24T4H.mjs +31 -0
- package/dist/image-loader.d.mts +119 -0
- package/dist/image-loader.d.ts +119 -0
- package/dist/image-loader.js +118 -0
- package/dist/image-loader.mjs +8 -0
- package/dist/index.d.mts +156 -0
- package/dist/index.d.ts +156 -0
- package/dist/index.js +383 -0
- package/dist/index.mjs +267 -0
- package/package.json +56 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stow Image Loader for Next.js
|
|
3
|
+
*
|
|
4
|
+
* Use Stow's image transformation service with Next.js Image component.
|
|
5
|
+
* Supports both vanity subdomain URLs ({slug}.stow.sh/{key}) and
|
|
6
|
+
* legacy path-based URLs (stow.sh/files/{bucketId}/{key}).
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* // next.config.js — global loader
|
|
11
|
+
* module.exports = {
|
|
12
|
+
* images: {
|
|
13
|
+
* loader: "custom",
|
|
14
|
+
* loaderFile: "./lib/stow-loader.ts",
|
|
15
|
+
* },
|
|
16
|
+
* };
|
|
17
|
+
*
|
|
18
|
+
* // lib/stow-loader.ts
|
|
19
|
+
* import { stowLoader } from "@howells/stow-next/image-loader";
|
|
20
|
+
* export default stowLoader;
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* // Per-component loader with crop options
|
|
26
|
+
* import { createStowLoader } from "@howells/stow-next/image-loader";
|
|
27
|
+
* import Image from "next/image";
|
|
28
|
+
*
|
|
29
|
+
* const avatarLoader = createStowLoader({
|
|
30
|
+
* fit: "cover",
|
|
31
|
+
* gravity: "face",
|
|
32
|
+
* aspectRatio: 1,
|
|
33
|
+
* defaultFormat: "webp",
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* function Avatar({ src }: { src: string }) {
|
|
37
|
+
* return <Image loader={avatarLoader} src={src} alt="Avatar" width={128} height={128} />;
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
interface ImageLoaderProps {
|
|
42
|
+
quality?: number;
|
|
43
|
+
src: string;
|
|
44
|
+
width: number;
|
|
45
|
+
}
|
|
46
|
+
interface StowLoaderConfig {
|
|
47
|
+
/**
|
|
48
|
+
* Fixed aspect ratio (width / height).
|
|
49
|
+
* When set, height is calculated from the requested width.
|
|
50
|
+
* Example: 1 for square, 16/9 for widescreen, 4/5 for portrait.
|
|
51
|
+
*/
|
|
52
|
+
aspectRatio?: number;
|
|
53
|
+
/**
|
|
54
|
+
* Base URL for the Stow service.
|
|
55
|
+
* @default "https://stow.sh"
|
|
56
|
+
*/
|
|
57
|
+
baseUrl?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Default output format.
|
|
60
|
+
*/
|
|
61
|
+
defaultFormat?: "webp" | "avif" | "jpeg" | "png";
|
|
62
|
+
/**
|
|
63
|
+
* Default image quality (1-100).
|
|
64
|
+
* @default 75
|
|
65
|
+
*/
|
|
66
|
+
defaultQuality?: number;
|
|
67
|
+
/**
|
|
68
|
+
* Resize fit mode (Cloudflare Images).
|
|
69
|
+
* - "scale-down" — shrink to fit, never enlarge
|
|
70
|
+
* - "contain" — fit within bounds preserving aspect ratio
|
|
71
|
+
* - "cover" — fill bounds, crop excess
|
|
72
|
+
* - "crop" — crop to exact dimensions
|
|
73
|
+
* - "pad" — fit within bounds, pad remaining space
|
|
74
|
+
*/
|
|
75
|
+
fit?: "scale-down" | "contain" | "cover" | "crop" | "pad";
|
|
76
|
+
/**
|
|
77
|
+
* Crop gravity / anchor point.
|
|
78
|
+
* - "auto" — subject-aware ML cropping
|
|
79
|
+
* - "face" — face-detection cropping
|
|
80
|
+
* - directional: "left", "right", "top", "bottom", "center"
|
|
81
|
+
*/
|
|
82
|
+
gravity?: "auto" | "face" | "left" | "right" | "top" | "bottom" | "center";
|
|
83
|
+
/**
|
|
84
|
+
* Bucket slug for proxying external images through Stow.
|
|
85
|
+
* When set, external URLs (http/https) are routed through proxy.stow.sh
|
|
86
|
+
* for R2 caching and on-the-fly image transforms.
|
|
87
|
+
*/
|
|
88
|
+
proxySlug?: string;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Create a custom image loader with configuration.
|
|
92
|
+
*
|
|
93
|
+
* Returns a stable function reference safe for use as a Next.js `loader` prop.
|
|
94
|
+
*/
|
|
95
|
+
declare function createStowLoader(config?: StowLoaderConfig): ({ src, width, quality, }: ImageLoaderProps) => string;
|
|
96
|
+
/**
|
|
97
|
+
* Default Stow image loader.
|
|
98
|
+
*
|
|
99
|
+
* Handles vanity subdomain URLs ({slug}.stow.sh) and legacy
|
|
100
|
+
* path-based URLs (stow.sh/files/...). Appends width and quality
|
|
101
|
+
* as transform query params.
|
|
102
|
+
*
|
|
103
|
+
* ```js
|
|
104
|
+
* // next.config.js
|
|
105
|
+
* module.exports = {
|
|
106
|
+
* images: {
|
|
107
|
+
* loader: "custom",
|
|
108
|
+
* loaderFile: "./lib/stow-loader.ts",
|
|
109
|
+
* },
|
|
110
|
+
* };
|
|
111
|
+
*
|
|
112
|
+
* // lib/stow-loader.ts
|
|
113
|
+
* import { stowLoader } from "@howells/stow-next/image-loader";
|
|
114
|
+
* export default stowLoader;
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
declare const stowLoader: ({ src, width, quality, }: ImageLoaderProps) => string;
|
|
118
|
+
|
|
119
|
+
export { type ImageLoaderProps, type StowLoaderConfig, createStowLoader, stowLoader };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/image-loader.ts
|
|
21
|
+
var image_loader_exports = {};
|
|
22
|
+
__export(image_loader_exports, {
|
|
23
|
+
createStowLoader: () => createStowLoader,
|
|
24
|
+
stowLoader: () => stowLoader
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(image_loader_exports);
|
|
27
|
+
var STOW_DOMAIN_PATTERN = /\.stow\.sh$/;
|
|
28
|
+
function isStowUrl(src) {
|
|
29
|
+
try {
|
|
30
|
+
const url = new URL(src);
|
|
31
|
+
return STOW_DOMAIN_PATTERN.test(url.hostname);
|
|
32
|
+
} catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function buildTransformParams(width, quality, config) {
|
|
37
|
+
const params = new URLSearchParams();
|
|
38
|
+
params.set("w", width.toString());
|
|
39
|
+
if (config.aspectRatio) {
|
|
40
|
+
params.set("h", Math.round(width / config.aspectRatio).toString());
|
|
41
|
+
}
|
|
42
|
+
params.set("q", quality.toString());
|
|
43
|
+
if (config.fit) {
|
|
44
|
+
params.set("fit", config.fit);
|
|
45
|
+
}
|
|
46
|
+
if (config.gravity) {
|
|
47
|
+
params.set("gravity", config.gravity);
|
|
48
|
+
}
|
|
49
|
+
if (config.defaultFormat) {
|
|
50
|
+
params.set("f", config.defaultFormat);
|
|
51
|
+
}
|
|
52
|
+
return params;
|
|
53
|
+
}
|
|
54
|
+
function transformStowUrl(src, baseUrl, params) {
|
|
55
|
+
const url = new URL(src, baseUrl);
|
|
56
|
+
const pathname = url.pathname;
|
|
57
|
+
if (pathname.startsWith("/files/")) {
|
|
58
|
+
const transformPath = pathname.replace("/files/", "/transform/");
|
|
59
|
+
return `${baseUrl}${transformPath}?${params.toString()}`;
|
|
60
|
+
}
|
|
61
|
+
if (pathname.startsWith("/transform/")) {
|
|
62
|
+
return `${baseUrl}${pathname}?${params.toString()}`;
|
|
63
|
+
}
|
|
64
|
+
return `${src}${src.includes("?") ? "&" : "?"}${params.toString()}`;
|
|
65
|
+
}
|
|
66
|
+
function createStowLoader(config = {}) {
|
|
67
|
+
const {
|
|
68
|
+
baseUrl = "https://stow.sh",
|
|
69
|
+
defaultQuality = 75,
|
|
70
|
+
defaultFormat,
|
|
71
|
+
proxySlug,
|
|
72
|
+
fit,
|
|
73
|
+
gravity,
|
|
74
|
+
aspectRatio
|
|
75
|
+
} = config;
|
|
76
|
+
return function stowLoader2({
|
|
77
|
+
src,
|
|
78
|
+
width,
|
|
79
|
+
quality
|
|
80
|
+
}) {
|
|
81
|
+
const resolvedQuality = quality || defaultQuality;
|
|
82
|
+
const paramConfig = { defaultFormat, fit, gravity, aspectRatio };
|
|
83
|
+
if (isStowUrl(src)) {
|
|
84
|
+
const params = buildTransformParams(width, resolvedQuality, paramConfig);
|
|
85
|
+
return `${src}${src.includes("?") ? "&" : "?"}${params.toString()}`;
|
|
86
|
+
}
|
|
87
|
+
if (src.startsWith(baseUrl) || src.startsWith("/files/")) {
|
|
88
|
+
const params = buildTransformParams(width, resolvedQuality, paramConfig);
|
|
89
|
+
return transformStowUrl(src, baseUrl, params);
|
|
90
|
+
}
|
|
91
|
+
if (proxySlug && (src.startsWith("http://") || src.startsWith("https://"))) {
|
|
92
|
+
const params = new URLSearchParams();
|
|
93
|
+
params.set("url", src);
|
|
94
|
+
params.set("w", width.toString());
|
|
95
|
+
if (aspectRatio) {
|
|
96
|
+
params.set("h", Math.round(width / aspectRatio).toString());
|
|
97
|
+
}
|
|
98
|
+
params.set("q", resolvedQuality.toString());
|
|
99
|
+
if (fit) {
|
|
100
|
+
params.set("fit", fit);
|
|
101
|
+
}
|
|
102
|
+
if (gravity) {
|
|
103
|
+
params.set("gravity", gravity);
|
|
104
|
+
}
|
|
105
|
+
if (defaultFormat) {
|
|
106
|
+
params.set("f", defaultFormat);
|
|
107
|
+
}
|
|
108
|
+
return `https://proxy.stow.sh/${proxySlug}/?${params.toString()}`;
|
|
109
|
+
}
|
|
110
|
+
return src;
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
var stowLoader = createStowLoader();
|
|
114
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
115
|
+
0 && (module.exports = {
|
|
116
|
+
createStowLoader,
|
|
117
|
+
stowLoader
|
|
118
|
+
});
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
export { StowLoaderConfig, createStowLoader, stowLoader } from './image-loader.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Stow Next.js Integration
|
|
6
|
+
*
|
|
7
|
+
* Provides Next.js-specific utilities for Stow file storage:
|
|
8
|
+
* - Route handlers for direct uploads (presign + confirm)
|
|
9
|
+
* - Image loader for next/image optimization
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // app/api/stow/presign/route.ts
|
|
14
|
+
* import { createPresignHandler } from "@howells/stow-next";
|
|
15
|
+
* import { StowServer } from "@howells/stow-server";
|
|
16
|
+
*
|
|
17
|
+
* const stow = new StowServer(process.env.STOW_API_KEY!);
|
|
18
|
+
* export const POST = createPresignHandler({ stow });
|
|
19
|
+
*
|
|
20
|
+
* // app/api/stow/confirm/route.ts
|
|
21
|
+
* import { createConfirmHandler } from "@howells/stow-next";
|
|
22
|
+
* export const POST = createConfirmHandler({ stow });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
interface CorsConfig {
|
|
27
|
+
/** Allowed headers (default: ["Content-Type"]) */
|
|
28
|
+
allowedHeaders?: string[];
|
|
29
|
+
/** Max age for preflight cache in seconds (default: 86400 = 24 hours) */
|
|
30
|
+
maxAge?: number;
|
|
31
|
+
/** Allowed methods (default: ["POST", "OPTIONS"]) */
|
|
32
|
+
methods?: string[];
|
|
33
|
+
/** Allowed origins (default: "*") */
|
|
34
|
+
origin?: string | string[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create an OPTIONS handler for CORS preflight requests
|
|
38
|
+
*/
|
|
39
|
+
declare function createCorsPreflightHandler(config?: CorsConfig): () => NextResponse;
|
|
40
|
+
interface StowServerLike {
|
|
41
|
+
confirmUpload: (request: {
|
|
42
|
+
fileKey: string;
|
|
43
|
+
size: number;
|
|
44
|
+
contentType: string;
|
|
45
|
+
}) => Promise<{
|
|
46
|
+
key: string;
|
|
47
|
+
url: string | null;
|
|
48
|
+
size: number;
|
|
49
|
+
contentType: string;
|
|
50
|
+
}>;
|
|
51
|
+
getPresignedUrl: (request: {
|
|
52
|
+
filename: string;
|
|
53
|
+
contentType: string;
|
|
54
|
+
size: number;
|
|
55
|
+
route?: string;
|
|
56
|
+
}) => Promise<{
|
|
57
|
+
dedupe: true;
|
|
58
|
+
key: string;
|
|
59
|
+
url: string | null;
|
|
60
|
+
size: number;
|
|
61
|
+
contentType: string;
|
|
62
|
+
} | {
|
|
63
|
+
fileKey: string;
|
|
64
|
+
uploadUrl: string;
|
|
65
|
+
r2Key: string;
|
|
66
|
+
confirmUrl: string;
|
|
67
|
+
dedupe?: false;
|
|
68
|
+
}>;
|
|
69
|
+
}
|
|
70
|
+
interface PresignHandlerConfig {
|
|
71
|
+
/** Allowed content types (supports wildcards like "image/*") */
|
|
72
|
+
allowedTypes?: string[];
|
|
73
|
+
/** CORS configuration (enabled by default for browser uploads) */
|
|
74
|
+
cors?: CorsConfig | false;
|
|
75
|
+
/** Maximum file size in bytes */
|
|
76
|
+
maxSize?: number;
|
|
77
|
+
/** Default route for organizing files */
|
|
78
|
+
route?: string;
|
|
79
|
+
/** Stow server instance */
|
|
80
|
+
stow: StowServerLike;
|
|
81
|
+
/** Custom validation function */
|
|
82
|
+
validate?: (request: {
|
|
83
|
+
filename: string;
|
|
84
|
+
contentType: string;
|
|
85
|
+
size: number;
|
|
86
|
+
}) => Promise<boolean | string> | boolean | string;
|
|
87
|
+
}
|
|
88
|
+
interface ConfirmHandlerConfig {
|
|
89
|
+
/** CORS configuration (enabled by default for browser uploads) */
|
|
90
|
+
cors?: CorsConfig | false;
|
|
91
|
+
/** Called after upload is confirmed */
|
|
92
|
+
onUploadComplete?: (result: {
|
|
93
|
+
key: string;
|
|
94
|
+
url: string | null;
|
|
95
|
+
size: number;
|
|
96
|
+
contentType: string;
|
|
97
|
+
}) => Promise<void> | void;
|
|
98
|
+
/** Stow server instance */
|
|
99
|
+
stow: StowServerLike;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Create a Next.js route handler for presigning uploads.
|
|
103
|
+
* This is called by @howells/stow-client to get a presigned URL for direct R2 upload.
|
|
104
|
+
*
|
|
105
|
+
* Returns both POST handler and OPTIONS handler for CORS preflight.
|
|
106
|
+
*/
|
|
107
|
+
declare function createPresignHandler(config: PresignHandlerConfig): (request: NextRequest) => Promise<NextResponse>;
|
|
108
|
+
/**
|
|
109
|
+
* Create a Next.js route handler for confirming uploads.
|
|
110
|
+
* This is called by @howells/stow-client after uploading to R2.
|
|
111
|
+
*
|
|
112
|
+
* Returns both POST handler and OPTIONS handler for CORS preflight.
|
|
113
|
+
*/
|
|
114
|
+
declare function createConfirmHandler(config: ConfirmHandlerConfig): (request: NextRequest) => Promise<NextResponse>;
|
|
115
|
+
interface StowLike {
|
|
116
|
+
uploadFile: (file: Blob, options?: {
|
|
117
|
+
filename?: string;
|
|
118
|
+
contentType?: string;
|
|
119
|
+
route?: string;
|
|
120
|
+
}) => Promise<{
|
|
121
|
+
key: string;
|
|
122
|
+
url: string | null;
|
|
123
|
+
size: number;
|
|
124
|
+
contentType: string;
|
|
125
|
+
}>;
|
|
126
|
+
}
|
|
127
|
+
interface UploadHandlerConfig {
|
|
128
|
+
/** Allowed content types (supports wildcards like "image/*") */
|
|
129
|
+
allowedTypes?: string[];
|
|
130
|
+
/** Maximum file size in bytes */
|
|
131
|
+
maxSize?: number;
|
|
132
|
+
/** Called before upload starts */
|
|
133
|
+
onUploadBegin?: (file: File) => Promise<void> | void;
|
|
134
|
+
/** Called after upload completes */
|
|
135
|
+
onUploadComplete?: (result: {
|
|
136
|
+
key: string;
|
|
137
|
+
url: string | null;
|
|
138
|
+
size: number;
|
|
139
|
+
contentType: string;
|
|
140
|
+
}) => Promise<void> | void;
|
|
141
|
+
/** Optional route for organizing files */
|
|
142
|
+
route?: string;
|
|
143
|
+
/** Stow server instance */
|
|
144
|
+
stow: StowLike;
|
|
145
|
+
/** Custom validation function */
|
|
146
|
+
validate?: (file: File) => Promise<boolean | string> | boolean | string;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Create a Next.js route handler for proxied file uploads.
|
|
150
|
+
*
|
|
151
|
+
* @deprecated Use createPresignHandler + createConfirmHandler for direct uploads.
|
|
152
|
+
* Proxied uploads are limited by serverless payload limits (~4.5MB on Vercel).
|
|
153
|
+
*/
|
|
154
|
+
declare function createUploadHandler(config: UploadHandlerConfig): (request: NextRequest) => Promise<NextResponse>;
|
|
155
|
+
|
|
156
|
+
export { type ConfirmHandlerConfig, type CorsConfig, type PresignHandlerConfig, type StowLike, type StowServerLike, type UploadHandlerConfig, createConfirmHandler, createCorsPreflightHandler, createPresignHandler, createUploadHandler };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
export { StowLoaderConfig, createStowLoader, stowLoader } from './image-loader.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Stow Next.js Integration
|
|
6
|
+
*
|
|
7
|
+
* Provides Next.js-specific utilities for Stow file storage:
|
|
8
|
+
* - Route handlers for direct uploads (presign + confirm)
|
|
9
|
+
* - Image loader for next/image optimization
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // app/api/stow/presign/route.ts
|
|
14
|
+
* import { createPresignHandler } from "@howells/stow-next";
|
|
15
|
+
* import { StowServer } from "@howells/stow-server";
|
|
16
|
+
*
|
|
17
|
+
* const stow = new StowServer(process.env.STOW_API_KEY!);
|
|
18
|
+
* export const POST = createPresignHandler({ stow });
|
|
19
|
+
*
|
|
20
|
+
* // app/api/stow/confirm/route.ts
|
|
21
|
+
* import { createConfirmHandler } from "@howells/stow-next";
|
|
22
|
+
* export const POST = createConfirmHandler({ stow });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
interface CorsConfig {
|
|
27
|
+
/** Allowed headers (default: ["Content-Type"]) */
|
|
28
|
+
allowedHeaders?: string[];
|
|
29
|
+
/** Max age for preflight cache in seconds (default: 86400 = 24 hours) */
|
|
30
|
+
maxAge?: number;
|
|
31
|
+
/** Allowed methods (default: ["POST", "OPTIONS"]) */
|
|
32
|
+
methods?: string[];
|
|
33
|
+
/** Allowed origins (default: "*") */
|
|
34
|
+
origin?: string | string[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create an OPTIONS handler for CORS preflight requests
|
|
38
|
+
*/
|
|
39
|
+
declare function createCorsPreflightHandler(config?: CorsConfig): () => NextResponse;
|
|
40
|
+
interface StowServerLike {
|
|
41
|
+
confirmUpload: (request: {
|
|
42
|
+
fileKey: string;
|
|
43
|
+
size: number;
|
|
44
|
+
contentType: string;
|
|
45
|
+
}) => Promise<{
|
|
46
|
+
key: string;
|
|
47
|
+
url: string | null;
|
|
48
|
+
size: number;
|
|
49
|
+
contentType: string;
|
|
50
|
+
}>;
|
|
51
|
+
getPresignedUrl: (request: {
|
|
52
|
+
filename: string;
|
|
53
|
+
contentType: string;
|
|
54
|
+
size: number;
|
|
55
|
+
route?: string;
|
|
56
|
+
}) => Promise<{
|
|
57
|
+
dedupe: true;
|
|
58
|
+
key: string;
|
|
59
|
+
url: string | null;
|
|
60
|
+
size: number;
|
|
61
|
+
contentType: string;
|
|
62
|
+
} | {
|
|
63
|
+
fileKey: string;
|
|
64
|
+
uploadUrl: string;
|
|
65
|
+
r2Key: string;
|
|
66
|
+
confirmUrl: string;
|
|
67
|
+
dedupe?: false;
|
|
68
|
+
}>;
|
|
69
|
+
}
|
|
70
|
+
interface PresignHandlerConfig {
|
|
71
|
+
/** Allowed content types (supports wildcards like "image/*") */
|
|
72
|
+
allowedTypes?: string[];
|
|
73
|
+
/** CORS configuration (enabled by default for browser uploads) */
|
|
74
|
+
cors?: CorsConfig | false;
|
|
75
|
+
/** Maximum file size in bytes */
|
|
76
|
+
maxSize?: number;
|
|
77
|
+
/** Default route for organizing files */
|
|
78
|
+
route?: string;
|
|
79
|
+
/** Stow server instance */
|
|
80
|
+
stow: StowServerLike;
|
|
81
|
+
/** Custom validation function */
|
|
82
|
+
validate?: (request: {
|
|
83
|
+
filename: string;
|
|
84
|
+
contentType: string;
|
|
85
|
+
size: number;
|
|
86
|
+
}) => Promise<boolean | string> | boolean | string;
|
|
87
|
+
}
|
|
88
|
+
interface ConfirmHandlerConfig {
|
|
89
|
+
/** CORS configuration (enabled by default for browser uploads) */
|
|
90
|
+
cors?: CorsConfig | false;
|
|
91
|
+
/** Called after upload is confirmed */
|
|
92
|
+
onUploadComplete?: (result: {
|
|
93
|
+
key: string;
|
|
94
|
+
url: string | null;
|
|
95
|
+
size: number;
|
|
96
|
+
contentType: string;
|
|
97
|
+
}) => Promise<void> | void;
|
|
98
|
+
/** Stow server instance */
|
|
99
|
+
stow: StowServerLike;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Create a Next.js route handler for presigning uploads.
|
|
103
|
+
* This is called by @howells/stow-client to get a presigned URL for direct R2 upload.
|
|
104
|
+
*
|
|
105
|
+
* Returns both POST handler and OPTIONS handler for CORS preflight.
|
|
106
|
+
*/
|
|
107
|
+
declare function createPresignHandler(config: PresignHandlerConfig): (request: NextRequest) => Promise<NextResponse>;
|
|
108
|
+
/**
|
|
109
|
+
* Create a Next.js route handler for confirming uploads.
|
|
110
|
+
* This is called by @howells/stow-client after uploading to R2.
|
|
111
|
+
*
|
|
112
|
+
* Returns both POST handler and OPTIONS handler for CORS preflight.
|
|
113
|
+
*/
|
|
114
|
+
declare function createConfirmHandler(config: ConfirmHandlerConfig): (request: NextRequest) => Promise<NextResponse>;
|
|
115
|
+
interface StowLike {
|
|
116
|
+
uploadFile: (file: Blob, options?: {
|
|
117
|
+
filename?: string;
|
|
118
|
+
contentType?: string;
|
|
119
|
+
route?: string;
|
|
120
|
+
}) => Promise<{
|
|
121
|
+
key: string;
|
|
122
|
+
url: string | null;
|
|
123
|
+
size: number;
|
|
124
|
+
contentType: string;
|
|
125
|
+
}>;
|
|
126
|
+
}
|
|
127
|
+
interface UploadHandlerConfig {
|
|
128
|
+
/** Allowed content types (supports wildcards like "image/*") */
|
|
129
|
+
allowedTypes?: string[];
|
|
130
|
+
/** Maximum file size in bytes */
|
|
131
|
+
maxSize?: number;
|
|
132
|
+
/** Called before upload starts */
|
|
133
|
+
onUploadBegin?: (file: File) => Promise<void> | void;
|
|
134
|
+
/** Called after upload completes */
|
|
135
|
+
onUploadComplete?: (result: {
|
|
136
|
+
key: string;
|
|
137
|
+
url: string | null;
|
|
138
|
+
size: number;
|
|
139
|
+
contentType: string;
|
|
140
|
+
}) => Promise<void> | void;
|
|
141
|
+
/** Optional route for organizing files */
|
|
142
|
+
route?: string;
|
|
143
|
+
/** Stow server instance */
|
|
144
|
+
stow: StowLike;
|
|
145
|
+
/** Custom validation function */
|
|
146
|
+
validate?: (file: File) => Promise<boolean | string> | boolean | string;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Create a Next.js route handler for proxied file uploads.
|
|
150
|
+
*
|
|
151
|
+
* @deprecated Use createPresignHandler + createConfirmHandler for direct uploads.
|
|
152
|
+
* Proxied uploads are limited by serverless payload limits (~4.5MB on Vercel).
|
|
153
|
+
*/
|
|
154
|
+
declare function createUploadHandler(config: UploadHandlerConfig): (request: NextRequest) => Promise<NextResponse>;
|
|
155
|
+
|
|
156
|
+
export { type ConfirmHandlerConfig, type CorsConfig, type PresignHandlerConfig, type StowLike, type StowServerLike, type UploadHandlerConfig, createConfirmHandler, createCorsPreflightHandler, createPresignHandler, createUploadHandler };
|