@edgestore/server 0.0.0-alpha.12 → 0.0.0-alpha.14
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/adapters/next/app/index.d.ts +4 -1
- package/dist/adapters/next/app/index.d.ts.map +1 -1
- package/dist/adapters/next/app/index.js +24 -4
- package/dist/adapters/next/app/index.mjs +24 -4
- package/dist/adapters/next/pages/index.d.ts +4 -1
- package/dist/adapters/next/pages/index.d.ts.map +1 -1
- package/dist/adapters/next/pages/index.js +18 -4
- package/dist/adapters/next/pages/index.mjs +18 -4
- package/dist/adapters/shared.d.ts +4 -3
- package/dist/adapters/shared.d.ts.map +1 -1
- package/dist/core/client/index.d.ts +19 -9
- package/dist/core/client/index.d.ts.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +21 -3
- package/dist/core/index.mjs +22 -4
- package/dist/core/internals/bucketBuilder.d.ts +98 -29
- package/dist/core/internals/bucketBuilder.d.ts.map +1 -1
- package/dist/core/sdk/index.d.ts +4 -4
- package/dist/core/sdk/index.d.ts.map +1 -1
- package/dist/{index-3cc4d530.js → index-0a168903.js} +4 -2
- package/dist/{index-ca41982b.mjs → index-579b8015.mjs} +4 -2
- package/dist/{index-3999aae6.js → index-62d969e5.js} +4 -2
- package/dist/index.js +18 -9
- package/dist/index.mjs +18 -9
- package/dist/providers/edgestore/index.d.ts +0 -1
- package/dist/providers/edgestore/index.d.ts.map +1 -1
- package/dist/providers/edgestore/index.js +4 -3
- package/dist/providers/edgestore/index.mjs +4 -3
- package/dist/providers/types.d.ts +2 -4
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/{shared-43667670.mjs → shared-2a9c8307.mjs} +34 -3
- package/dist/{shared-f7607e44.js → shared-ae739a04.js} +34 -3
- package/dist/{shared-6bef8919.js → shared-fac1b0a0.js} +35 -3
- package/package.json +7 -5
- package/src/adapters/next/app/index.ts +37 -6
- package/src/adapters/next/pages/index.ts +33 -6
- package/src/adapters/shared.ts +41 -9
- package/src/core/client/index.ts +50 -17
- package/src/core/index.ts +1 -0
- package/src/core/internals/bucketBuilder.ts +129 -41
- package/src/core/sdk/index.ts +8 -6
- package/src/providers/edgestore/index.ts +3 -4
- package/src/providers/types.ts +6 -4
|
@@ -51,7 +51,7 @@ async function init(params) {
|
|
|
51
51
|
maxAge: DEFAULT_MAX_AGE
|
|
52
52
|
}));
|
|
53
53
|
}
|
|
54
|
-
const baseUrl = provider.getBaseUrl();
|
|
54
|
+
const baseUrl = await provider.getBaseUrl();
|
|
55
55
|
return {
|
|
56
56
|
newCookies,
|
|
57
57
|
token,
|
|
@@ -78,6 +78,7 @@ async function requestUpload(params) {
|
|
|
78
78
|
fileInfo: {
|
|
79
79
|
size: fileInfo.size,
|
|
80
80
|
type: fileInfo.type,
|
|
81
|
+
fileName: fileInfo.fileName,
|
|
81
82
|
extension: fileInfo.extension,
|
|
82
83
|
replaceTargetUrl: fileInfo.replaceTargetUrl
|
|
83
84
|
}
|
|
@@ -94,6 +95,36 @@ async function requestUpload(params) {
|
|
|
94
95
|
});
|
|
95
96
|
}
|
|
96
97
|
}
|
|
98
|
+
if (bucket._def.bucketConfig?.maxSize) {
|
|
99
|
+
if (fileInfo.size > bucket._def.bucketConfig.maxSize) {
|
|
100
|
+
throw new EdgeStoreError({
|
|
101
|
+
code: 'BAD_REQUEST',
|
|
102
|
+
message: `File size is too big. Max size is ${bucket._def.bucketConfig.maxSize}`
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (bucket._def.bucketConfig?.accept) {
|
|
107
|
+
const accept = bucket._def.bucketConfig.accept;
|
|
108
|
+
let accepted = false;
|
|
109
|
+
for (const acceptedMimeType of accept){
|
|
110
|
+
if (acceptedMimeType.endsWith('/*')) {
|
|
111
|
+
const mimeType = acceptedMimeType.replace('/*', '');
|
|
112
|
+
if (fileInfo.type.startsWith(mimeType)) {
|
|
113
|
+
accepted = true;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
} else if (fileInfo.type === acceptedMimeType) {
|
|
117
|
+
accepted = true;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (!accepted) {
|
|
122
|
+
throw new EdgeStoreError({
|
|
123
|
+
code: 'BAD_REQUEST',
|
|
124
|
+
message: `"${fileInfo.type}" is not allowed. Accepted types are ${JSON.stringify(accept)}`
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
97
128
|
const path = buildPath({
|
|
98
129
|
fileInfo,
|
|
99
130
|
bucket,
|
|
@@ -159,12 +190,12 @@ async function deleteFile(params) {
|
|
|
159
190
|
if (!bucket._def.beforeDelete) {
|
|
160
191
|
throw new Error('You need to define beforeDelete if you want to delete files directly from the frontend.');
|
|
161
192
|
}
|
|
162
|
-
const
|
|
193
|
+
const fileInfo = await provider.getFile({
|
|
163
194
|
url
|
|
164
195
|
});
|
|
165
196
|
const canDelete = await bucket._def.beforeDelete({
|
|
166
197
|
ctx,
|
|
167
|
-
|
|
198
|
+
fileInfo
|
|
168
199
|
});
|
|
169
200
|
if (!canDelete) {
|
|
170
201
|
throw new Error('Delete not allowed');
|
|
@@ -53,7 +53,7 @@ async function init(params) {
|
|
|
53
53
|
maxAge: DEFAULT_MAX_AGE
|
|
54
54
|
}));
|
|
55
55
|
}
|
|
56
|
-
const baseUrl = provider.getBaseUrl();
|
|
56
|
+
const baseUrl = await provider.getBaseUrl();
|
|
57
57
|
return {
|
|
58
58
|
newCookies,
|
|
59
59
|
token,
|
|
@@ -80,6 +80,7 @@ async function requestUpload(params) {
|
|
|
80
80
|
fileInfo: {
|
|
81
81
|
size: fileInfo.size,
|
|
82
82
|
type: fileInfo.type,
|
|
83
|
+
fileName: fileInfo.fileName,
|
|
83
84
|
extension: fileInfo.extension,
|
|
84
85
|
replaceTargetUrl: fileInfo.replaceTargetUrl
|
|
85
86
|
}
|
|
@@ -96,6 +97,36 @@ async function requestUpload(params) {
|
|
|
96
97
|
});
|
|
97
98
|
}
|
|
98
99
|
}
|
|
100
|
+
if (bucket._def.bucketConfig?.maxSize) {
|
|
101
|
+
if (fileInfo.size > bucket._def.bucketConfig.maxSize) {
|
|
102
|
+
throw new EdgeStoreError({
|
|
103
|
+
code: 'BAD_REQUEST',
|
|
104
|
+
message: `File size is too big. Max size is ${bucket._def.bucketConfig.maxSize}`
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (bucket._def.bucketConfig?.accept) {
|
|
109
|
+
const accept = bucket._def.bucketConfig.accept;
|
|
110
|
+
let accepted = false;
|
|
111
|
+
for (const acceptedMimeType of accept){
|
|
112
|
+
if (acceptedMimeType.endsWith('/*')) {
|
|
113
|
+
const mimeType = acceptedMimeType.replace('/*', '');
|
|
114
|
+
if (fileInfo.type.startsWith(mimeType)) {
|
|
115
|
+
accepted = true;
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
} else if (fileInfo.type === acceptedMimeType) {
|
|
119
|
+
accepted = true;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (!accepted) {
|
|
124
|
+
throw new EdgeStoreError({
|
|
125
|
+
code: 'BAD_REQUEST',
|
|
126
|
+
message: `"${fileInfo.type}" is not allowed. Accepted types are ${JSON.stringify(accept)}`
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
99
130
|
const path = buildPath({
|
|
100
131
|
fileInfo,
|
|
101
132
|
bucket,
|
|
@@ -161,12 +192,12 @@ async function deleteFile(params) {
|
|
|
161
192
|
if (!bucket._def.beforeDelete) {
|
|
162
193
|
throw new Error('You need to define beforeDelete if you want to delete files directly from the frontend.');
|
|
163
194
|
}
|
|
164
|
-
const
|
|
195
|
+
const fileInfo = await provider.getFile({
|
|
165
196
|
url
|
|
166
197
|
});
|
|
167
198
|
const canDelete = await bucket._def.beforeDelete({
|
|
168
199
|
ctx,
|
|
169
|
-
|
|
200
|
+
fileInfo
|
|
170
201
|
});
|
|
171
202
|
if (!canDelete) {
|
|
172
203
|
throw new Error('Delete not allowed');
|
|
@@ -48,7 +48,7 @@ async function init(params) {
|
|
|
48
48
|
maxAge: DEFAULT_MAX_AGE,
|
|
49
49
|
}));
|
|
50
50
|
}
|
|
51
|
-
const baseUrl = provider.getBaseUrl();
|
|
51
|
+
const baseUrl = await provider.getBaseUrl();
|
|
52
52
|
return {
|
|
53
53
|
newCookies,
|
|
54
54
|
token,
|
|
@@ -75,6 +75,7 @@ async function requestUpload(params) {
|
|
|
75
75
|
fileInfo: {
|
|
76
76
|
size: fileInfo.size,
|
|
77
77
|
type: fileInfo.type,
|
|
78
|
+
fileName: fileInfo.fileName,
|
|
78
79
|
extension: fileInfo.extension,
|
|
79
80
|
replaceTargetUrl: fileInfo.replaceTargetUrl,
|
|
80
81
|
},
|
|
@@ -91,6 +92,37 @@ async function requestUpload(params) {
|
|
|
91
92
|
});
|
|
92
93
|
}
|
|
93
94
|
}
|
|
95
|
+
if (bucket._def.bucketConfig?.maxSize) {
|
|
96
|
+
if (fileInfo.size > bucket._def.bucketConfig.maxSize) {
|
|
97
|
+
throw new EdgeStoreError({
|
|
98
|
+
code: 'BAD_REQUEST',
|
|
99
|
+
message: `File size is too big. Max size is ${bucket._def.bucketConfig.maxSize}`,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (bucket._def.bucketConfig?.accept) {
|
|
104
|
+
const accept = bucket._def.bucketConfig.accept;
|
|
105
|
+
let accepted = false;
|
|
106
|
+
for (const acceptedMimeType of accept) {
|
|
107
|
+
if (acceptedMimeType.endsWith('/*')) {
|
|
108
|
+
const mimeType = acceptedMimeType.replace('/*', '');
|
|
109
|
+
if (fileInfo.type.startsWith(mimeType)) {
|
|
110
|
+
accepted = true;
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else if (fileInfo.type === acceptedMimeType) {
|
|
115
|
+
accepted = true;
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!accepted) {
|
|
120
|
+
throw new EdgeStoreError({
|
|
121
|
+
code: 'BAD_REQUEST',
|
|
122
|
+
message: `"${fileInfo.type}" is not allowed. Accepted types are ${JSON.stringify(accept)}`,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
94
126
|
const path = buildPath({
|
|
95
127
|
fileInfo,
|
|
96
128
|
bucket,
|
|
@@ -150,12 +182,12 @@ async function deleteFile(params) {
|
|
|
150
182
|
if (!bucket._def.beforeDelete) {
|
|
151
183
|
throw new Error('You need to define beforeDelete if you want to delete files directly from the frontend.');
|
|
152
184
|
}
|
|
153
|
-
const
|
|
185
|
+
const fileInfo = await provider.getFile({
|
|
154
186
|
url,
|
|
155
187
|
});
|
|
156
188
|
const canDelete = await bucket._def.beforeDelete({
|
|
157
189
|
ctx,
|
|
158
|
-
|
|
190
|
+
fileInfo,
|
|
159
191
|
});
|
|
160
192
|
if (!canDelete) {
|
|
161
193
|
throw new Error('Delete not allowed');
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edgestore/server",
|
|
3
|
-
"version": "0.0.0-alpha.
|
|
4
|
-
"description": "
|
|
5
|
-
"homepage": "https://
|
|
6
|
-
"repository": "https://github.com/edgestorejs/
|
|
3
|
+
"version": "0.0.0-alpha.14",
|
|
4
|
+
"description": "The best DX for uploading files from your Next.js app",
|
|
5
|
+
"homepage": "https://edgestore.dev",
|
|
6
|
+
"repository": "https://github.com/edgestorejs/edgestore.git",
|
|
7
7
|
"author": "Ravi <me@ravi.com>",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"module": "dist/index.mjs",
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
"react",
|
|
13
13
|
"nodejs",
|
|
14
14
|
"nextjs",
|
|
15
|
+
"upload",
|
|
16
|
+
"file",
|
|
15
17
|
"image",
|
|
16
18
|
"cdn",
|
|
17
19
|
"edgestore",
|
|
@@ -92,5 +94,5 @@
|
|
|
92
94
|
"typescript": "^5.1.6",
|
|
93
95
|
"zod": "^3.21.4"
|
|
94
96
|
},
|
|
95
|
-
"gitHead": "
|
|
97
|
+
"gitHead": "6e0044e7fcb252014e5a4fc9257d54e897f42b84"
|
|
96
98
|
}
|
|
@@ -20,18 +20,26 @@ export type CreateContextOptions = {
|
|
|
20
20
|
req: NextRequest;
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
export type Config<TCtx> =
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
23
|
+
export type Config<TCtx> = TCtx extends Record<string, never>
|
|
24
|
+
? {
|
|
25
|
+
provider?: Provider;
|
|
26
|
+
router: EdgeStoreRouter<TCtx>;
|
|
27
|
+
}
|
|
28
|
+
: {
|
|
29
|
+
provider?: Provider;
|
|
30
|
+
router: EdgeStoreRouter<TCtx>;
|
|
31
|
+
createContext: (opts: CreateContextOptions) => MaybePromise<TCtx>;
|
|
32
|
+
};
|
|
28
33
|
|
|
29
34
|
export function createEdgeStoreNextHandler<TCtx>(config: Config<TCtx>) {
|
|
30
35
|
const { provider = EdgeStoreProvider() } = config;
|
|
31
36
|
return async (req: NextRequest) => {
|
|
32
37
|
try {
|
|
33
38
|
if (req.nextUrl.pathname === '/api/edgestore/init') {
|
|
34
|
-
const ctx =
|
|
39
|
+
const ctx =
|
|
40
|
+
'createContext' in config
|
|
41
|
+
? await config.createContext({ req })
|
|
42
|
+
: ({} as TCtx);
|
|
35
43
|
const { newCookies, token, baseUrl } = await init({
|
|
36
44
|
ctx,
|
|
37
45
|
provider,
|
|
@@ -88,6 +96,29 @@ export function createEdgeStoreNextHandler<TCtx>(config: Config<TCtx>) {
|
|
|
88
96
|
return new Response(null, {
|
|
89
97
|
status: 200,
|
|
90
98
|
});
|
|
99
|
+
} else if (req.nextUrl.pathname === '/api/edgestore/proxy-file') {
|
|
100
|
+
const url = req.nextUrl.searchParams.get('url');
|
|
101
|
+
if (typeof url === 'string') {
|
|
102
|
+
const proxyRes = await fetch(url, {
|
|
103
|
+
headers: {
|
|
104
|
+
cookie: req.cookies.toString() ?? '',
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const data = await proxyRes.arrayBuffer();
|
|
109
|
+
return new Response(data, {
|
|
110
|
+
status: proxyRes.status,
|
|
111
|
+
headers: {
|
|
112
|
+
'Content-Type':
|
|
113
|
+
proxyRes.headers.get('Content-Type') ??
|
|
114
|
+
'application/octet-stream',
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
} else {
|
|
118
|
+
return new Response(null, {
|
|
119
|
+
status: 400,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
91
122
|
} else {
|
|
92
123
|
return new Response(null, {
|
|
93
124
|
status: 404,
|
|
@@ -21,18 +21,26 @@ export type CreateContextOptions = {
|
|
|
21
21
|
res: NextApiResponse;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
export type Config<TCtx> =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
24
|
+
export type Config<TCtx> = TCtx extends Record<string, never>
|
|
25
|
+
? {
|
|
26
|
+
provider?: Provider;
|
|
27
|
+
router: EdgeStoreRouter<TCtx>;
|
|
28
|
+
}
|
|
29
|
+
: {
|
|
30
|
+
provider?: Provider;
|
|
31
|
+
router: EdgeStoreRouter<TCtx>;
|
|
32
|
+
createContext: (opts: CreateContextOptions) => MaybePromise<TCtx>;
|
|
33
|
+
};
|
|
29
34
|
|
|
30
35
|
export function createEdgeStoreNextHandler<TCtx>(config: Config<TCtx>) {
|
|
31
36
|
const { provider = EdgeStoreProvider() } = config;
|
|
32
37
|
return async (req: NextApiRequest, res: NextApiResponse) => {
|
|
33
38
|
try {
|
|
34
39
|
if (req.url === '/api/edgestore/init') {
|
|
35
|
-
const ctx =
|
|
40
|
+
const ctx =
|
|
41
|
+
'createContext' in config
|
|
42
|
+
? await config.createContext({ req, res })
|
|
43
|
+
: ({} as TCtx);
|
|
36
44
|
const { newCookies, token, baseUrl } = await init({
|
|
37
45
|
ctx,
|
|
38
46
|
provider,
|
|
@@ -69,6 +77,25 @@ export function createEdgeStoreNextHandler<TCtx>(config: Config<TCtx>) {
|
|
|
69
77
|
ctxToken: req.cookies['edgestore-ctx'],
|
|
70
78
|
});
|
|
71
79
|
res.status(200).end();
|
|
80
|
+
} else if (req.url?.startsWith('/api/edgestore/proxy-file')) {
|
|
81
|
+
const { url } = req.query;
|
|
82
|
+
if (typeof url === 'string') {
|
|
83
|
+
const proxyRes = await fetch(url, {
|
|
84
|
+
headers: {
|
|
85
|
+
cookie: req.headers.cookie ?? '',
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const data = await proxyRes.arrayBuffer();
|
|
90
|
+
res.setHeader(
|
|
91
|
+
'Content-Type',
|
|
92
|
+
proxyRes.headers.get('Content-Type') ?? 'application/octet-stream',
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
res.end(Buffer.from(data));
|
|
96
|
+
} else {
|
|
97
|
+
res.status(400).end();
|
|
98
|
+
}
|
|
72
99
|
} else {
|
|
73
100
|
res.status(404).end();
|
|
74
101
|
}
|
package/src/adapters/shared.ts
CHANGED
|
@@ -2,11 +2,7 @@ import { hkdf } from '@panva/hkdf';
|
|
|
2
2
|
import { serialize } from 'cookie';
|
|
3
3
|
import { EncryptJWT, jwtDecrypt } from 'jose';
|
|
4
4
|
import { v4 as uuidv4 } from 'uuid';
|
|
5
|
-
import {
|
|
6
|
-
AnyBuilder,
|
|
7
|
-
AnyPath,
|
|
8
|
-
EdgeStoreRouter,
|
|
9
|
-
} from '../core/internals/bucketBuilder';
|
|
5
|
+
import { AnyBuilder, EdgeStoreRouter } from '../core/internals/bucketBuilder';
|
|
10
6
|
import EdgeStoreError from '../libs/errors/EdgeStoreError';
|
|
11
7
|
import { Provider } from '../providers/types';
|
|
12
8
|
import { IMAGE_MIME_TYPES } from './imageTypes';
|
|
@@ -39,7 +35,7 @@ export async function init<TCtx>(params: {
|
|
|
39
35
|
}),
|
|
40
36
|
);
|
|
41
37
|
}
|
|
42
|
-
const baseUrl = provider.getBaseUrl();
|
|
38
|
+
const baseUrl = await provider.getBaseUrl();
|
|
43
39
|
|
|
44
40
|
return {
|
|
45
41
|
newCookies,
|
|
@@ -55,6 +51,7 @@ export type RequestUploadBody = {
|
|
|
55
51
|
size: number;
|
|
56
52
|
type: string;
|
|
57
53
|
extension: string;
|
|
54
|
+
fileName?: string;
|
|
58
55
|
replaceTargetUrl?: string;
|
|
59
56
|
};
|
|
60
57
|
};
|
|
@@ -90,6 +87,7 @@ export async function requestUpload<TCtx>(params: {
|
|
|
90
87
|
fileInfo: {
|
|
91
88
|
size: fileInfo.size,
|
|
92
89
|
type: fileInfo.type,
|
|
90
|
+
fileName: fileInfo.fileName,
|
|
93
91
|
extension: fileInfo.extension,
|
|
94
92
|
replaceTargetUrl: fileInfo.replaceTargetUrl,
|
|
95
93
|
},
|
|
@@ -108,6 +106,40 @@ export async function requestUpload<TCtx>(params: {
|
|
|
108
106
|
}
|
|
109
107
|
}
|
|
110
108
|
|
|
109
|
+
if (bucket._def.bucketConfig?.maxSize) {
|
|
110
|
+
if (fileInfo.size > bucket._def.bucketConfig.maxSize) {
|
|
111
|
+
throw new EdgeStoreError({
|
|
112
|
+
code: 'BAD_REQUEST',
|
|
113
|
+
message: `File size is too big. Max size is ${bucket._def.bucketConfig.maxSize}`,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (bucket._def.bucketConfig?.accept) {
|
|
119
|
+
const accept = bucket._def.bucketConfig.accept;
|
|
120
|
+
let accepted = false;
|
|
121
|
+
for (const acceptedMimeType of accept) {
|
|
122
|
+
if (acceptedMimeType.endsWith('/*')) {
|
|
123
|
+
const mimeType = acceptedMimeType.replace('/*', '');
|
|
124
|
+
if (fileInfo.type.startsWith(mimeType)) {
|
|
125
|
+
accepted = true;
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
} else if (fileInfo.type === acceptedMimeType) {
|
|
129
|
+
accepted = true;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (!accepted) {
|
|
134
|
+
throw new EdgeStoreError({
|
|
135
|
+
code: 'BAD_REQUEST',
|
|
136
|
+
message: `"${
|
|
137
|
+
fileInfo.type
|
|
138
|
+
}" is not allowed. Accepted types are ${JSON.stringify(accept)}`,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
111
143
|
const path = buildPath({
|
|
112
144
|
fileInfo,
|
|
113
145
|
bucket,
|
|
@@ -207,12 +239,12 @@ export async function deleteFile<TCtx>(params: {
|
|
|
207
239
|
);
|
|
208
240
|
}
|
|
209
241
|
|
|
210
|
-
const
|
|
242
|
+
const fileInfo = await provider.getFile({
|
|
211
243
|
url,
|
|
212
244
|
});
|
|
213
245
|
const canDelete = await bucket._def.beforeDelete({
|
|
214
246
|
ctx,
|
|
215
|
-
|
|
247
|
+
fileInfo,
|
|
216
248
|
});
|
|
217
249
|
if (!canDelete) {
|
|
218
250
|
throw new Error('Delete not allowed');
|
|
@@ -274,7 +306,7 @@ function buildPath(params: {
|
|
|
274
306
|
};
|
|
275
307
|
}) {
|
|
276
308
|
const { bucket } = params;
|
|
277
|
-
const pathParams = bucket._def.path
|
|
309
|
+
const pathParams = bucket._def.path;
|
|
278
310
|
const path = pathParams.map((param) => {
|
|
279
311
|
const paramEntries = Object.entries(param);
|
|
280
312
|
if (paramEntries[0] === undefined) {
|
package/src/core/client/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { Simplify } from '../../types';
|
|
|
3
3
|
import {
|
|
4
4
|
AnyBuilder,
|
|
5
5
|
InferBucketPathKeys,
|
|
6
|
+
InferBucketPathObject,
|
|
6
7
|
InferMetadataObject,
|
|
7
8
|
} from '../internals/bucketBuilder';
|
|
8
9
|
import { initEdgeStoreSdk } from '../sdk';
|
|
@@ -12,9 +13,7 @@ export type GetFileRes<TBucket extends AnyBuilder> = {
|
|
|
12
13
|
size: number;
|
|
13
14
|
uploadedAt: Date;
|
|
14
15
|
metadata: InferMetadataObject<TBucket>;
|
|
15
|
-
path:
|
|
16
|
-
[TKey in InferBucketPathKeys<TBucket>]: string;
|
|
17
|
-
};
|
|
16
|
+
path: InferBucketPathObject<TBucket>;
|
|
18
17
|
};
|
|
19
18
|
|
|
20
19
|
type Filter<TBucket extends AnyBuilder> = {
|
|
@@ -38,18 +37,22 @@ export type ListFilesRequest<TBucket extends AnyBuilder> = {
|
|
|
38
37
|
};
|
|
39
38
|
|
|
40
39
|
export type ListFilesResponse<TBucket extends AnyBuilder> = {
|
|
41
|
-
data:
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
40
|
+
data: TBucket['_def']['type'] extends 'IMAGE'
|
|
41
|
+
? {
|
|
42
|
+
url: string;
|
|
43
|
+
thumbnailUrl: string | null;
|
|
44
|
+
size: number;
|
|
45
|
+
uploadedAt: Date;
|
|
46
|
+
metadata: InferMetadataObject<TBucket>;
|
|
47
|
+
path: InferBucketPathObject<TBucket>;
|
|
48
|
+
}[]
|
|
49
|
+
: {
|
|
50
|
+
url: string;
|
|
51
|
+
size: number;
|
|
52
|
+
uploadedAt: Date;
|
|
53
|
+
metadata: InferMetadataObject<TBucket>;
|
|
54
|
+
path: InferBucketPathObject<TBucket>;
|
|
55
|
+
}[];
|
|
53
56
|
pagination: {
|
|
54
57
|
currentPage: number;
|
|
55
58
|
totalPages: number;
|
|
@@ -96,6 +99,14 @@ export function initEdgeStoreClient<TRouter extends AnyRouter>(config: {
|
|
|
96
99
|
router: TRouter;
|
|
97
100
|
accessKey?: string;
|
|
98
101
|
secretKey?: string;
|
|
102
|
+
/**
|
|
103
|
+
* The base URL of your application.
|
|
104
|
+
*
|
|
105
|
+
* This is only needed for getting protected files on a development environment.
|
|
106
|
+
*
|
|
107
|
+
* @example http://localhost:3000/api/edgestore
|
|
108
|
+
*/
|
|
109
|
+
baseUrl?: string;
|
|
99
110
|
}) {
|
|
100
111
|
const sdk = initEdgeStoreSdk({
|
|
101
112
|
accessKey: config.accessKey,
|
|
@@ -112,7 +123,7 @@ export function initEdgeStoreClient<TRouter extends AnyRouter>(config: {
|
|
|
112
123
|
async getFile(params) {
|
|
113
124
|
const res = await sdk.getFile(params);
|
|
114
125
|
return {
|
|
115
|
-
url: res.url,
|
|
126
|
+
url: getUrl(res.url, config.baseUrl),
|
|
116
127
|
size: res.size,
|
|
117
128
|
uploadedAt: new Date(res.uploadedAt),
|
|
118
129
|
metadata: res.metadata,
|
|
@@ -171,7 +182,7 @@ export function initEdgeStoreClient<TRouter extends AnyRouter>(config: {
|
|
|
171
182
|
|
|
172
183
|
const files = res.data.map((file) => {
|
|
173
184
|
return {
|
|
174
|
-
url: file.url,
|
|
185
|
+
url: getUrl(file.url, config.baseUrl),
|
|
175
186
|
thumbnailUrl: file.thumbnailUrl,
|
|
176
187
|
size: file.size,
|
|
177
188
|
uploadedAt: new Date(file.uploadedAt),
|
|
@@ -193,6 +204,28 @@ export function initEdgeStoreClient<TRouter extends AnyRouter>(config: {
|
|
|
193
204
|
});
|
|
194
205
|
}
|
|
195
206
|
|
|
207
|
+
/**
|
|
208
|
+
* Protected files need third-party cookies to work.
|
|
209
|
+
* Since third party cookies doesn't work on localhost,
|
|
210
|
+
* we need to proxy the file through the server.
|
|
211
|
+
*/
|
|
212
|
+
function getUrl(url: string, baseUrl?: string) {
|
|
213
|
+
if (process.env.NODE_ENV === 'development' && !url.includes('/_public/')) {
|
|
214
|
+
if (!baseUrl) {
|
|
215
|
+
throw new Error(
|
|
216
|
+
'Missing baseUrl. You need to pass the baseUrl to `initEdgeStoreClient` to get protected files in development.',
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
const proxyUrl = new URL(baseUrl);
|
|
220
|
+
proxyUrl.pathname = `${proxyUrl.pathname}/proxy-file`;
|
|
221
|
+
proxyUrl.search = new URLSearchParams({
|
|
222
|
+
url,
|
|
223
|
+
}).toString();
|
|
224
|
+
return proxyUrl.toString();
|
|
225
|
+
}
|
|
226
|
+
return url;
|
|
227
|
+
}
|
|
228
|
+
|
|
196
229
|
export type InferClientResponse<TRouter extends AnyRouter> = {
|
|
197
230
|
[TBucketName in keyof TRouter['buckets']]: {
|
|
198
231
|
[TClienFn in keyof EdgeStoreClient<TRouter>[TBucketName]]: Simplify<
|