@edgestore/server 0.0.0-alpha.12
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 +86 -0
- package/adapters/next/app/index.d.ts +1 -0
- package/adapters/next/app/index.js +1 -0
- package/adapters/next/index.d.ts +1 -0
- package/adapters/next/index.js +1 -0
- package/adapters/next/pages/index.d.ts +1 -0
- package/adapters/next/pages/index.js +1 -0
- package/core/index.d.ts +1 -0
- package/core/index.js +1 -0
- package/dist/adapters/imageTypes.d.ts +2 -0
- package/dist/adapters/imageTypes.d.ts.map +1 -0
- package/dist/adapters/next/app/index.d.ts +14 -0
- package/dist/adapters/next/app/index.d.ts.map +1 -0
- package/dist/adapters/next/app/index.js +95 -0
- package/dist/adapters/next/app/index.mjs +91 -0
- package/dist/adapters/next/pages/index.d.ts +15 -0
- package/dist/adapters/next/pages/index.d.ts.map +1 -0
- package/dist/adapters/next/pages/index.js +69 -0
- package/dist/adapters/next/pages/index.mjs +65 -0
- package/dist/adapters/shared.d.ts +79 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/core/client/index.d.ts +81 -0
- package/dist/core/client/index.d.ts.map +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +96 -0
- package/dist/core/index.mjs +91 -0
- package/dist/core/internals/bucketBuilder.d.ts +199 -0
- package/dist/core/internals/bucketBuilder.d.ts.map +1 -0
- package/dist/core/internals/createPathParamProxy.d.ts +21 -0
- package/dist/core/internals/createPathParamProxy.d.ts.map +1 -0
- package/dist/core/sdk/index.d.ts +200 -0
- package/dist/core/sdk/index.d.ts.map +1 -0
- package/dist/index-3999aae6.js +187 -0
- package/dist/index-3cc4d530.js +183 -0
- package/dist/index-ca41982b.mjs +183 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +213 -0
- package/dist/index.mjs +209 -0
- package/dist/libs/errors/EdgeStoreCredentialsError.d.ts +5 -0
- package/dist/libs/errors/EdgeStoreCredentialsError.d.ts.map +1 -0
- package/dist/libs/errors/EdgeStoreError.d.ts +16 -0
- package/dist/libs/errors/EdgeStoreError.d.ts.map +1 -0
- package/dist/providers/aws/index.d.ts +9 -0
- package/dist/providers/aws/index.d.ts.map +1 -0
- package/dist/providers/aws/index.js +81 -0
- package/dist/providers/aws/index.mjs +77 -0
- package/dist/providers/edgestore/index.d.ts +8 -0
- package/dist/providers/edgestore/index.d.ts.map +1 -0
- package/dist/providers/edgestore/index.js +121 -0
- package/dist/providers/edgestore/index.mjs +117 -0
- package/dist/providers/index.d.ts +3 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/types.d.ts +91 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/shared-43667670.mjs +232 -0
- package/dist/shared-6bef8919.js +227 -0
- package/dist/shared-f7607e44.js +239 -0
- package/dist/types.d.ts +88 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +96 -0
- package/providers/aws/index.d.ts +1 -0
- package/providers/aws/index.js +1 -0
- package/providers/edgestore/index.d.ts +1 -0
- package/providers/edgestore/index.js +1 -0
- package/src/adapters/imageTypes.ts +10 -0
- package/src/adapters/next/app/index.ts +111 -0
- package/src/adapters/next/pages/index.ts +84 -0
- package/src/adapters/shared.ts +306 -0
- package/src/core/client/index.ts +202 -0
- package/src/core/index.ts +10 -0
- package/src/core/internals/bucketBuilder.ts +462 -0
- package/src/core/internals/createPathParamProxy.ts +40 -0
- package/src/core/sdk/index.ts +381 -0
- package/src/index.ts +1 -0
- package/src/libs/errors/EdgeStoreCredentialsError.ts +12 -0
- package/src/libs/errors/EdgeStoreError.ts +25 -0
- package/src/providers/aws/index.ts +109 -0
- package/src/providers/edgestore/index.ts +140 -0
- package/src/providers/index.ts +2 -0
- package/src/providers/types.ts +107 -0
- package/src/types.ts +139 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { hkdf } from '@panva/hkdf';
|
|
2
|
+
import { serialize } from 'cookie';
|
|
3
|
+
import { EncryptJWT, jwtDecrypt } from 'jose';
|
|
4
|
+
import { v4 } from 'uuid';
|
|
5
|
+
|
|
6
|
+
const EDGE_STORE_ERROR_CODES = {
|
|
7
|
+
BAD_REQUEST: 400,
|
|
8
|
+
UNAUTHORIZED: 401,
|
|
9
|
+
};
|
|
10
|
+
class EdgeStoreError extends Error {
|
|
11
|
+
constructor(opts) {
|
|
12
|
+
super(opts.message);
|
|
13
|
+
this.name = 'EdgeStoreError';
|
|
14
|
+
this.code = opts.code;
|
|
15
|
+
this.cause = opts.cause;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const IMAGE_MIME_TYPES = [
|
|
20
|
+
'image/jpeg',
|
|
21
|
+
'image/png',
|
|
22
|
+
'image/gif',
|
|
23
|
+
'image/webp',
|
|
24
|
+
'image/svg+xml',
|
|
25
|
+
'image/tiff',
|
|
26
|
+
'image/bmp',
|
|
27
|
+
'image/x-icon',
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
// TODO: change it to 1 hour when we have a way to refresh the token
|
|
31
|
+
const DEFAULT_MAX_AGE = 30 * 24 * 60 * 60; // 30 days
|
|
32
|
+
async function init(params) {
|
|
33
|
+
const { ctx, provider, router } = params;
|
|
34
|
+
const ctxToken = await encryptJWT(ctx);
|
|
35
|
+
const { token } = await provider.init({
|
|
36
|
+
ctx,
|
|
37
|
+
router: router,
|
|
38
|
+
});
|
|
39
|
+
const newCookies = [
|
|
40
|
+
serialize('edgestore-ctx', ctxToken, {
|
|
41
|
+
path: '/',
|
|
42
|
+
maxAge: DEFAULT_MAX_AGE,
|
|
43
|
+
}),
|
|
44
|
+
];
|
|
45
|
+
if (token) {
|
|
46
|
+
newCookies.push(serialize('edgestore-token', token, {
|
|
47
|
+
path: '/',
|
|
48
|
+
maxAge: DEFAULT_MAX_AGE,
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
const baseUrl = provider.getBaseUrl();
|
|
52
|
+
return {
|
|
53
|
+
newCookies,
|
|
54
|
+
token,
|
|
55
|
+
baseUrl,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async function requestUpload(params) {
|
|
59
|
+
const { provider, router, ctxToken, body: { bucketName, input, fileInfo }, } = params;
|
|
60
|
+
if (!ctxToken) {
|
|
61
|
+
throw new EdgeStoreError({
|
|
62
|
+
message: 'Missing edgestore-ctx cookie',
|
|
63
|
+
code: 'UNAUTHORIZED',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
const ctx = await getContext(ctxToken);
|
|
67
|
+
const bucket = router.buckets[bucketName];
|
|
68
|
+
if (!bucket) {
|
|
69
|
+
throw new Error(`Bucket ${bucketName} not found`);
|
|
70
|
+
}
|
|
71
|
+
if (bucket._def.beforeUpload) {
|
|
72
|
+
const canUpload = await bucket._def.beforeUpload?.({
|
|
73
|
+
ctx,
|
|
74
|
+
input,
|
|
75
|
+
fileInfo: {
|
|
76
|
+
size: fileInfo.size,
|
|
77
|
+
type: fileInfo.type,
|
|
78
|
+
extension: fileInfo.extension,
|
|
79
|
+
replaceTargetUrl: fileInfo.replaceTargetUrl,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
if (!canUpload) {
|
|
83
|
+
throw new Error('Upload not allowed');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (bucket._def.type === 'IMAGE') {
|
|
87
|
+
if (!IMAGE_MIME_TYPES.includes(fileInfo.type)) {
|
|
88
|
+
throw new EdgeStoreError({
|
|
89
|
+
code: 'BAD_REQUEST',
|
|
90
|
+
message: 'Only images are allowed in this bucket',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const path = buildPath({
|
|
95
|
+
fileInfo,
|
|
96
|
+
bucket,
|
|
97
|
+
pathAttrs: { ctx, input },
|
|
98
|
+
});
|
|
99
|
+
const metadata = await bucket._def.metadata?.({ ctx, input });
|
|
100
|
+
const isPublic = bucket._def.accessControl === undefined;
|
|
101
|
+
const requestUploadRes = await provider.requestUpload({
|
|
102
|
+
bucketName,
|
|
103
|
+
bucketType: bucket._def.type,
|
|
104
|
+
fileInfo: {
|
|
105
|
+
...fileInfo,
|
|
106
|
+
path,
|
|
107
|
+
isPublic,
|
|
108
|
+
metadata,
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
return {
|
|
112
|
+
...requestUploadRes,
|
|
113
|
+
size: fileInfo.size,
|
|
114
|
+
uploadedAt: new Date().toISOString(),
|
|
115
|
+
path,
|
|
116
|
+
metadata,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
async function requestUploadParts(params) {
|
|
120
|
+
const { provider, router, ctxToken, body: { multipart, path }, } = params;
|
|
121
|
+
if (!ctxToken) {
|
|
122
|
+
throw new EdgeStoreError({
|
|
123
|
+
message: 'Missing edgestore-ctx cookie',
|
|
124
|
+
code: 'UNAUTHORIZED',
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
await getContext(ctxToken); // just to check if the token is valid
|
|
128
|
+
const bucket = router.buckets[multipart.uploadId];
|
|
129
|
+
if (!bucket) {
|
|
130
|
+
throw new Error(`Bucket ${multipart.uploadId} not found`);
|
|
131
|
+
}
|
|
132
|
+
return await provider.requestUploadParts({
|
|
133
|
+
multipart,
|
|
134
|
+
path,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
async function deleteFile(params) {
|
|
138
|
+
const { provider, router, ctxToken, body: { bucketName, url }, } = params;
|
|
139
|
+
if (!ctxToken) {
|
|
140
|
+
throw new EdgeStoreError({
|
|
141
|
+
message: 'Missing edgestore-ctx cookie',
|
|
142
|
+
code: 'UNAUTHORIZED',
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
const ctx = await getContext(ctxToken);
|
|
146
|
+
const bucket = router.buckets[bucketName];
|
|
147
|
+
if (!bucket) {
|
|
148
|
+
throw new Error(`Bucket ${bucketName} not found`);
|
|
149
|
+
}
|
|
150
|
+
if (!bucket._def.beforeDelete) {
|
|
151
|
+
throw new Error('You need to define beforeDelete if you want to delete files directly from the frontend.');
|
|
152
|
+
}
|
|
153
|
+
const file = await provider.getFile({
|
|
154
|
+
url,
|
|
155
|
+
});
|
|
156
|
+
const canDelete = await bucket._def.beforeDelete({
|
|
157
|
+
ctx,
|
|
158
|
+
file,
|
|
159
|
+
});
|
|
160
|
+
if (!canDelete) {
|
|
161
|
+
throw new Error('Delete not allowed');
|
|
162
|
+
}
|
|
163
|
+
await provider.deleteFile({
|
|
164
|
+
bucket,
|
|
165
|
+
url,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
async function encryptJWT(ctx) {
|
|
169
|
+
const secret = process.env.EDGE_STORE_JWT_SECRET ?? process.env.EDGE_STORE_SECRET_KEY;
|
|
170
|
+
if (!secret) {
|
|
171
|
+
throw new Error('EDGE_STORE_JWT_SECRET or EDGE_STORE_SECRET_KEY is not defined');
|
|
172
|
+
}
|
|
173
|
+
const encryptionSecret = await getDerivedEncryptionKey(secret);
|
|
174
|
+
return await new EncryptJWT(ctx)
|
|
175
|
+
.setProtectedHeader({ alg: 'dir', enc: 'A256GCM' })
|
|
176
|
+
.setIssuedAt()
|
|
177
|
+
.setExpirationTime(Date.now() / 1000 + DEFAULT_MAX_AGE)
|
|
178
|
+
.setJti(v4())
|
|
179
|
+
.encrypt(encryptionSecret);
|
|
180
|
+
}
|
|
181
|
+
async function decryptJWT(token) {
|
|
182
|
+
const secret = process.env.EDGE_STORE_JWT_SECRET ?? process.env.EDGE_STORE_SECRET_KEY;
|
|
183
|
+
if (!secret) {
|
|
184
|
+
throw new Error('EDGE_STORE_JWT_SECRET or EDGE_STORE_SECRET_KEY is not set');
|
|
185
|
+
}
|
|
186
|
+
const encryptionSecret = await getDerivedEncryptionKey(secret);
|
|
187
|
+
const { payload } = await jwtDecrypt(token, encryptionSecret, {
|
|
188
|
+
clockTolerance: 15,
|
|
189
|
+
});
|
|
190
|
+
return payload;
|
|
191
|
+
}
|
|
192
|
+
async function getDerivedEncryptionKey(secret) {
|
|
193
|
+
return await hkdf('sha256', secret, '', 'Edge Store Generated Encryption Key', 32);
|
|
194
|
+
}
|
|
195
|
+
function buildPath(params) {
|
|
196
|
+
const { bucket } = params;
|
|
197
|
+
const pathParams = bucket._def.path;
|
|
198
|
+
const path = pathParams.map((param) => {
|
|
199
|
+
const paramEntries = Object.entries(param);
|
|
200
|
+
if (paramEntries[0] === undefined) {
|
|
201
|
+
throw new Error('Missing path param');
|
|
202
|
+
}
|
|
203
|
+
const [key, value] = paramEntries[0];
|
|
204
|
+
// this is a string like: "ctx.xxx" or "input.yyy.zzz"
|
|
205
|
+
const currParamVal = value()
|
|
206
|
+
.split('.')
|
|
207
|
+
.reduce((acc2, key) => {
|
|
208
|
+
if (acc2[key] === undefined) {
|
|
209
|
+
throw new Error(`Missing key ${key} in ${JSON.stringify(acc2)}`);
|
|
210
|
+
}
|
|
211
|
+
return acc2[key];
|
|
212
|
+
}, params.pathAttrs);
|
|
213
|
+
return {
|
|
214
|
+
key,
|
|
215
|
+
value: currParamVal,
|
|
216
|
+
};
|
|
217
|
+
});
|
|
218
|
+
return path;
|
|
219
|
+
}
|
|
220
|
+
async function getContext(token) {
|
|
221
|
+
if (!token) {
|
|
222
|
+
throw new Error('No token');
|
|
223
|
+
}
|
|
224
|
+
return await decryptJWT(token);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export { EdgeStoreError as E, requestUploadParts as a, EDGE_STORE_ERROR_CODES as b, deleteFile as d, init as i, requestUpload as r };
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var hkdf = require('@panva/hkdf');
|
|
4
|
+
var cookie = require('cookie');
|
|
5
|
+
var jose = require('jose');
|
|
6
|
+
var uuid = require('uuid');
|
|
7
|
+
var _define_property = require('@swc/helpers/_/_define_property');
|
|
8
|
+
|
|
9
|
+
const EDGE_STORE_ERROR_CODES = {
|
|
10
|
+
BAD_REQUEST: 400,
|
|
11
|
+
UNAUTHORIZED: 401
|
|
12
|
+
};
|
|
13
|
+
class EdgeStoreError extends Error {
|
|
14
|
+
constructor(opts){
|
|
15
|
+
super(opts.message);
|
|
16
|
+
_define_property._(this, "cause", void 0);
|
|
17
|
+
_define_property._(this, "code", void 0);
|
|
18
|
+
this.name = 'EdgeStoreError';
|
|
19
|
+
this.code = opts.code;
|
|
20
|
+
this.cause = opts.cause;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const IMAGE_MIME_TYPES = [
|
|
25
|
+
'image/jpeg',
|
|
26
|
+
'image/png',
|
|
27
|
+
'image/gif',
|
|
28
|
+
'image/webp',
|
|
29
|
+
'image/svg+xml',
|
|
30
|
+
'image/tiff',
|
|
31
|
+
'image/bmp',
|
|
32
|
+
'image/x-icon'
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
// TODO: change it to 1 hour when we have a way to refresh the token
|
|
36
|
+
const DEFAULT_MAX_AGE = 30 * 24 * 60 * 60; // 30 days
|
|
37
|
+
async function init(params) {
|
|
38
|
+
const { ctx, provider, router } = params;
|
|
39
|
+
const ctxToken = await encryptJWT(ctx);
|
|
40
|
+
const { token } = await provider.init({
|
|
41
|
+
ctx,
|
|
42
|
+
router: router
|
|
43
|
+
});
|
|
44
|
+
const newCookies = [
|
|
45
|
+
cookie.serialize('edgestore-ctx', ctxToken, {
|
|
46
|
+
path: '/',
|
|
47
|
+
maxAge: DEFAULT_MAX_AGE
|
|
48
|
+
})
|
|
49
|
+
];
|
|
50
|
+
if (token) {
|
|
51
|
+
newCookies.push(cookie.serialize('edgestore-token', token, {
|
|
52
|
+
path: '/',
|
|
53
|
+
maxAge: DEFAULT_MAX_AGE
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
const baseUrl = provider.getBaseUrl();
|
|
57
|
+
return {
|
|
58
|
+
newCookies,
|
|
59
|
+
token,
|
|
60
|
+
baseUrl
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async function requestUpload(params) {
|
|
64
|
+
const { provider, router, ctxToken, body: { bucketName, input, fileInfo } } = params;
|
|
65
|
+
if (!ctxToken) {
|
|
66
|
+
throw new EdgeStoreError({
|
|
67
|
+
message: 'Missing edgestore-ctx cookie',
|
|
68
|
+
code: 'UNAUTHORIZED'
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const ctx = await getContext(ctxToken);
|
|
72
|
+
const bucket = router.buckets[bucketName];
|
|
73
|
+
if (!bucket) {
|
|
74
|
+
throw new Error(`Bucket ${bucketName} not found`);
|
|
75
|
+
}
|
|
76
|
+
if (bucket._def.beforeUpload) {
|
|
77
|
+
const canUpload = await bucket._def.beforeUpload?.({
|
|
78
|
+
ctx,
|
|
79
|
+
input,
|
|
80
|
+
fileInfo: {
|
|
81
|
+
size: fileInfo.size,
|
|
82
|
+
type: fileInfo.type,
|
|
83
|
+
extension: fileInfo.extension,
|
|
84
|
+
replaceTargetUrl: fileInfo.replaceTargetUrl
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
if (!canUpload) {
|
|
88
|
+
throw new Error('Upload not allowed');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (bucket._def.type === 'IMAGE') {
|
|
92
|
+
if (!IMAGE_MIME_TYPES.includes(fileInfo.type)) {
|
|
93
|
+
throw new EdgeStoreError({
|
|
94
|
+
code: 'BAD_REQUEST',
|
|
95
|
+
message: 'Only images are allowed in this bucket'
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const path = buildPath({
|
|
100
|
+
fileInfo,
|
|
101
|
+
bucket,
|
|
102
|
+
pathAttrs: {
|
|
103
|
+
ctx,
|
|
104
|
+
input
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
const metadata = await bucket._def.metadata?.({
|
|
108
|
+
ctx,
|
|
109
|
+
input
|
|
110
|
+
});
|
|
111
|
+
const isPublic = bucket._def.accessControl === undefined;
|
|
112
|
+
const requestUploadRes = await provider.requestUpload({
|
|
113
|
+
bucketName,
|
|
114
|
+
bucketType: bucket._def.type,
|
|
115
|
+
fileInfo: {
|
|
116
|
+
...fileInfo,
|
|
117
|
+
path,
|
|
118
|
+
isPublic,
|
|
119
|
+
metadata
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
...requestUploadRes,
|
|
124
|
+
size: fileInfo.size,
|
|
125
|
+
uploadedAt: new Date().toISOString(),
|
|
126
|
+
path,
|
|
127
|
+
metadata
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
async function requestUploadParts(params) {
|
|
131
|
+
const { provider, router, ctxToken, body: { multipart, path } } = params;
|
|
132
|
+
if (!ctxToken) {
|
|
133
|
+
throw new EdgeStoreError({
|
|
134
|
+
message: 'Missing edgestore-ctx cookie',
|
|
135
|
+
code: 'UNAUTHORIZED'
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
await getContext(ctxToken); // just to check if the token is valid
|
|
139
|
+
const bucket = router.buckets[multipart.uploadId];
|
|
140
|
+
if (!bucket) {
|
|
141
|
+
throw new Error(`Bucket ${multipart.uploadId} not found`);
|
|
142
|
+
}
|
|
143
|
+
return await provider.requestUploadParts({
|
|
144
|
+
multipart,
|
|
145
|
+
path
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
async function deleteFile(params) {
|
|
149
|
+
const { provider, router, ctxToken, body: { bucketName, url } } = params;
|
|
150
|
+
if (!ctxToken) {
|
|
151
|
+
throw new EdgeStoreError({
|
|
152
|
+
message: 'Missing edgestore-ctx cookie',
|
|
153
|
+
code: 'UNAUTHORIZED'
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
const ctx = await getContext(ctxToken);
|
|
157
|
+
const bucket = router.buckets[bucketName];
|
|
158
|
+
if (!bucket) {
|
|
159
|
+
throw new Error(`Bucket ${bucketName} not found`);
|
|
160
|
+
}
|
|
161
|
+
if (!bucket._def.beforeDelete) {
|
|
162
|
+
throw new Error('You need to define beforeDelete if you want to delete files directly from the frontend.');
|
|
163
|
+
}
|
|
164
|
+
const file = await provider.getFile({
|
|
165
|
+
url
|
|
166
|
+
});
|
|
167
|
+
const canDelete = await bucket._def.beforeDelete({
|
|
168
|
+
ctx,
|
|
169
|
+
file
|
|
170
|
+
});
|
|
171
|
+
if (!canDelete) {
|
|
172
|
+
throw new Error('Delete not allowed');
|
|
173
|
+
}
|
|
174
|
+
await provider.deleteFile({
|
|
175
|
+
bucket,
|
|
176
|
+
url
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
async function encryptJWT(ctx) {
|
|
180
|
+
const secret = process.env.EDGE_STORE_JWT_SECRET ?? process.env.EDGE_STORE_SECRET_KEY;
|
|
181
|
+
if (!secret) {
|
|
182
|
+
throw new Error('EDGE_STORE_JWT_SECRET or EDGE_STORE_SECRET_KEY is not defined');
|
|
183
|
+
}
|
|
184
|
+
const encryptionSecret = await getDerivedEncryptionKey(secret);
|
|
185
|
+
return await new jose.EncryptJWT(ctx).setProtectedHeader({
|
|
186
|
+
alg: 'dir',
|
|
187
|
+
enc: 'A256GCM'
|
|
188
|
+
}).setIssuedAt().setExpirationTime(Date.now() / 1000 + DEFAULT_MAX_AGE).setJti(uuid.v4()).encrypt(encryptionSecret);
|
|
189
|
+
}
|
|
190
|
+
async function decryptJWT(token) {
|
|
191
|
+
const secret = process.env.EDGE_STORE_JWT_SECRET ?? process.env.EDGE_STORE_SECRET_KEY;
|
|
192
|
+
if (!secret) {
|
|
193
|
+
throw new Error('EDGE_STORE_JWT_SECRET or EDGE_STORE_SECRET_KEY is not set');
|
|
194
|
+
}
|
|
195
|
+
const encryptionSecret = await getDerivedEncryptionKey(secret);
|
|
196
|
+
const { payload } = await jose.jwtDecrypt(token, encryptionSecret, {
|
|
197
|
+
clockTolerance: 15
|
|
198
|
+
});
|
|
199
|
+
return payload;
|
|
200
|
+
}
|
|
201
|
+
async function getDerivedEncryptionKey(secret) {
|
|
202
|
+
return await hkdf.hkdf('sha256', secret, '', 'Edge Store Generated Encryption Key', 32);
|
|
203
|
+
}
|
|
204
|
+
function buildPath(params) {
|
|
205
|
+
const { bucket } = params;
|
|
206
|
+
const pathParams = bucket._def.path;
|
|
207
|
+
const path = pathParams.map((param)=>{
|
|
208
|
+
const paramEntries = Object.entries(param);
|
|
209
|
+
if (paramEntries[0] === undefined) {
|
|
210
|
+
throw new Error('Missing path param');
|
|
211
|
+
}
|
|
212
|
+
const [key, value] = paramEntries[0];
|
|
213
|
+
// this is a string like: "ctx.xxx" or "input.yyy.zzz"
|
|
214
|
+
const currParamVal = value().split('.').reduce((acc2, key)=>{
|
|
215
|
+
if (acc2[key] === undefined) {
|
|
216
|
+
throw new Error(`Missing key ${key} in ${JSON.stringify(acc2)}`);
|
|
217
|
+
}
|
|
218
|
+
return acc2[key];
|
|
219
|
+
}, params.pathAttrs);
|
|
220
|
+
return {
|
|
221
|
+
key,
|
|
222
|
+
value: currParamVal
|
|
223
|
+
};
|
|
224
|
+
});
|
|
225
|
+
return path;
|
|
226
|
+
}
|
|
227
|
+
async function getContext(token) {
|
|
228
|
+
if (!token) {
|
|
229
|
+
throw new Error('No token');
|
|
230
|
+
}
|
|
231
|
+
return await decryptJWT(token);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
exports.EDGE_STORE_ERROR_CODES = EDGE_STORE_ERROR_CODES;
|
|
235
|
+
exports.EdgeStoreError = EdgeStoreError;
|
|
236
|
+
exports.deleteFile = deleteFile;
|
|
237
|
+
exports.init = init;
|
|
238
|
+
exports.requestUpload = requestUpload;
|
|
239
|
+
exports.requestUploadParts = requestUploadParts;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @internal
|
|
3
|
+
*/
|
|
4
|
+
export type identity<TType> = TType;
|
|
5
|
+
export type InferOptional<TType, TKeys extends keyof TType> = Omit<TType, TKeys> & Partial<Pick<TType, TKeys>>;
|
|
6
|
+
export type UndefinedKeys<TType> = {
|
|
7
|
+
[K in keyof TType]: undefined extends TType[K] ? K : never;
|
|
8
|
+
}[keyof TType];
|
|
9
|
+
/**
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export type FlatOverwrite<TType, TWith> = InferOptional<{
|
|
13
|
+
[TKey in keyof TType | keyof TWith]: TKey extends keyof TWith ? TWith[TKey] : TKey extends keyof TType ? TType[TKey] : never;
|
|
14
|
+
}, UndefinedKeys<TType> | UndefinedKeys<TWith>>;
|
|
15
|
+
/**
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
export type IntersectionError<TKey extends string> = `The property '${TKey}' in your router collides with a built-in method, rename this router or procedure on your backend.`;
|
|
19
|
+
/**
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export type ProtectedIntersection<TType, TWith> = keyof TType & keyof TWith extends never ? TType & TWith : IntersectionError<string & keyof TType & keyof TWith>;
|
|
23
|
+
/**
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
export type Maybe<TType> = TType | null | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
export type ThenArg<TType> = TType extends PromiseLike<infer U> ? ThenArg<U> : TType;
|
|
31
|
+
/**
|
|
32
|
+
* @internal
|
|
33
|
+
* @see https://github.com/ianstormtaylor/superstruct/blob/7973400cd04d8ad92bbdc2b6f35acbfb3c934079/src/utils.ts#L323-L325
|
|
34
|
+
*/
|
|
35
|
+
export type Simplify<TType> = TType extends any[] | Date ? TType : {
|
|
36
|
+
[K in keyof TType]: TType[K];
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* @public
|
|
40
|
+
*/
|
|
41
|
+
export type Dict<TType> = Record<string, TType | undefined>;
|
|
42
|
+
/**
|
|
43
|
+
* @public
|
|
44
|
+
*/
|
|
45
|
+
export type MaybePromise<TType> = Promise<TType> | TType;
|
|
46
|
+
/**
|
|
47
|
+
* @internal
|
|
48
|
+
*
|
|
49
|
+
* Creates a "lower-priority" type inference.
|
|
50
|
+
* https://github.com/microsoft/TypeScript/issues/14829#issuecomment-322267089
|
|
51
|
+
*/
|
|
52
|
+
export type InferLast<TType> = TType & {
|
|
53
|
+
[KeyType in keyof TType]: TType[KeyType];
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* @public
|
|
57
|
+
*/
|
|
58
|
+
export type inferAsyncReturnType<TFunction extends (...args: any) => any> = ThenArg<ReturnType<TFunction>>;
|
|
59
|
+
export type FilterKeys<TObj extends object, TFilter> = {
|
|
60
|
+
[TKey in keyof TObj]: TObj[TKey] extends TFilter ? TKey : never;
|
|
61
|
+
}[keyof TObj];
|
|
62
|
+
/**
|
|
63
|
+
* @internal
|
|
64
|
+
*/
|
|
65
|
+
export type Filter<TObj extends object, TFilter> = Pick<TObj, FilterKeys<TObj, TFilter>>;
|
|
66
|
+
/**
|
|
67
|
+
* Unwrap return type if the type is a function (sync or async), else use the type as is
|
|
68
|
+
* @internal
|
|
69
|
+
*/
|
|
70
|
+
export type Unwrap<TType> = TType extends (...args: any[]) => infer R ? ThenArg<R> : TType;
|
|
71
|
+
/**
|
|
72
|
+
* Makes the object recursively optional.
|
|
73
|
+
* @internal
|
|
74
|
+
*/
|
|
75
|
+
export type DeepPartial<TObject> = TObject extends object ? {
|
|
76
|
+
[P in keyof TObject]?: DeepPartial<TObject[P]>;
|
|
77
|
+
} : TObject;
|
|
78
|
+
/**
|
|
79
|
+
* Get the keys of a union type.
|
|
80
|
+
* @internal
|
|
81
|
+
*/
|
|
82
|
+
export type KeysOfUnion<TUnion> = TUnion extends TUnion ? keyof TUnion extends string ? keyof TUnion : string : never;
|
|
83
|
+
/**
|
|
84
|
+
* Unify a union of objects into a single object.
|
|
85
|
+
* @internal
|
|
86
|
+
*/
|
|
87
|
+
export type UnifyUnion<TUnion> = Simplify<(TUnion extends any ? (k: TUnion) => void : never) extends (k: infer I) => void ? I : never>;
|
|
88
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,QAAQ,CAAC,KAAK,IAAI,KAAK,CAAC;AAEpC,MAAM,MAAM,aAAa,CAAC,KAAK,EAAE,KAAK,SAAS,MAAM,KAAK,IAAI,IAAI,CAChE,KAAK,EACL,KAAK,CACN,GACC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;AAE9B,MAAM,MAAM,aAAa,CAAC,KAAK,IAAI;KAChC,CAAC,IAAI,MAAM,KAAK,GAAG,SAAS,SAAS,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK;CAC3D,CAAC,MAAM,KAAK,CAAC,CAAC;AAEf;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,KAAK,EAAE,KAAK,IAAI,aAAa,CACrD;KACG,IAAI,IAAI,MAAM,KAAK,GAAG,MAAM,KAAK,GAAG,IAAI,SAAS,MAAM,KAAK,GACzD,KAAK,CAAC,IAAI,CAAC,GACX,IAAI,SAAS,MAAM,KAAK,GACxB,KAAK,CAAC,IAAI,CAAC,GACX,KAAK;CACV,EACD,aAAa,CAAC,KAAK,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAC5C,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,IAAI,SAAS,MAAM,IAC/C,iBAAiB,IAAI,oGAAoG,CAAC;AAE5H;;GAEG;AACH,MAAM,MAAM,qBAAqB,CAAC,KAAK,EAAE,KAAK,IAAI,MAAM,KAAK,GAC3D,MAAM,KAAK,SAAS,KAAK,GACvB,KAAK,GAAG,KAAK,GACb,iBAAiB,CAAC,MAAM,GAAG,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,CAAC;AAE1D;;GAEG;AACH,MAAM,MAAM,KAAK,CAAC,KAAK,IAAI,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC;AAEpD;;GAEG;AACH,MAAM,MAAM,OAAO,CAAC,KAAK,IAAI,KAAK,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GAC3D,OAAO,CAAC,CAAC,CAAC,GACV,KAAK,CAAC;AAEV;;;GAGG;AACH,MAAM,MAAM,QAAQ,CAAC,KAAK,IAAI,KAAK,SAAS,GAAG,EAAE,GAAG,IAAI,GACpD,KAAK,GACL;KAAG,CAAC,IAAI,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC;CAAE,CAAC;AACrC;;GAEG;AACH,MAAM,MAAM,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,KAAK,GAAG,SAAS,CAAC,CAAC;AAE5D;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,MAAM,SAAS,CAAC,KAAK,IAAI,KAAK,GAAG;KACpC,OAAO,IAAI,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC;CACzC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,oBAAoB,CAAC,SAAS,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,IACtE,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;AAEjC,MAAM,MAAM,UAAU,CAAC,IAAI,SAAS,MAAM,EAAE,OAAO,IAAI;KACpD,IAAI,IAAI,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,OAAO,GAAG,IAAI,GAAG,KAAK;CAChE,CAAC,MAAM,IAAI,CAAC,CAAC;AAEd;;GAEG;AACH,MAAM,MAAM,MAAM,CAAC,IAAI,SAAS,MAAM,EAAE,OAAO,IAAI,IAAI,CACrD,IAAI,EACJ,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAC1B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,MAAM,CAAC,KAAK,IAAI,KAAK,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,CAAC,GACjE,OAAO,CAAC,CAAC,CAAC,GACV,KAAK,CAAC;AAEV;;;GAGG;AACH,MAAM,MAAM,WAAW,CAAC,OAAO,IAAI,OAAO,SAAS,MAAM,GACrD;KACG,CAAC,IAAI,MAAM,OAAO,CAAC,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;CAC/C,GACD,OAAO,CAAC;AAEZ;;;GAGG;AACH,MAAM,MAAM,WAAW,CAAC,MAAM,IAAI,MAAM,SAAS,MAAM,GACnD,MAAM,MAAM,SAAS,MAAM,GACzB,MAAM,MAAM,GACZ,MAAM,GACR,KAAK,CAAC;AAEV;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,MAAM,IAAI,QAAQ,CACvC,CAAC,MAAM,SAAS,GAAG,GAAG,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,KAAK,CAAC,SAAS,CACzD,CAAC,EAAE,MAAM,CAAC,KACP,IAAI,GACL,CAAC,GACD,KAAK,CACV,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@edgestore/server",
|
|
3
|
+
"version": "0.0.0-alpha.12",
|
|
4
|
+
"description": "Image Handling for React/Next.js",
|
|
5
|
+
"homepage": "https://edge-store.com",
|
|
6
|
+
"repository": "https://github.com/edgestorejs/edge-store.git",
|
|
7
|
+
"author": "Ravi <me@ravi.com>",
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"module": "dist/index.mjs",
|
|
10
|
+
"typings": "dist/index.d.ts",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"react",
|
|
13
|
+
"nodejs",
|
|
14
|
+
"nextjs",
|
|
15
|
+
"image",
|
|
16
|
+
"cdn",
|
|
17
|
+
"edgestore",
|
|
18
|
+
"edge-store"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "rollup --config rollup.config.ts --configPlugin rollup-plugin-swc3",
|
|
22
|
+
"dev": "pnpm build --watch",
|
|
23
|
+
"codegen:entrypoints": "tsx entrypoints.script.ts",
|
|
24
|
+
"lint": "eslint --cache --ext \".js,.ts,.tsx\" --ignore-path ../../.gitignore --report-unused-disable-directives src"
|
|
25
|
+
},
|
|
26
|
+
"exports": {
|
|
27
|
+
"./package.json": "./package.json",
|
|
28
|
+
".": {
|
|
29
|
+
"import": "./dist/index.mjs",
|
|
30
|
+
"require": "./dist/index.js",
|
|
31
|
+
"default": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./core": {
|
|
34
|
+
"import": "./dist/core/index.mjs",
|
|
35
|
+
"require": "./dist/core/index.js",
|
|
36
|
+
"default": "./dist/core/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./adapters/next/pages": {
|
|
39
|
+
"import": "./dist/adapters/next/pages/index.mjs",
|
|
40
|
+
"require": "./dist/adapters/next/pages/index.js",
|
|
41
|
+
"default": "./dist/adapters/next/pages/index.js"
|
|
42
|
+
},
|
|
43
|
+
"./adapters/next/app": {
|
|
44
|
+
"import": "./dist/adapters/next/app/index.mjs",
|
|
45
|
+
"require": "./dist/adapters/next/app/index.js",
|
|
46
|
+
"default": "./dist/adapters/next/app/index.js"
|
|
47
|
+
},
|
|
48
|
+
"./providers/aws": {
|
|
49
|
+
"import": "./dist/providers/aws/index.mjs",
|
|
50
|
+
"require": "./dist/providers/aws/index.js",
|
|
51
|
+
"default": "./dist/providers/aws/index.js"
|
|
52
|
+
},
|
|
53
|
+
"./providers/edgestore": {
|
|
54
|
+
"import": "./dist/providers/edgestore/index.mjs",
|
|
55
|
+
"require": "./dist/providers/edgestore/index.js",
|
|
56
|
+
"default": "./dist/providers/edgestore/index.js"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"files": [
|
|
60
|
+
"dist",
|
|
61
|
+
"src",
|
|
62
|
+
"README.md",
|
|
63
|
+
"package.json",
|
|
64
|
+
"core",
|
|
65
|
+
"adapters",
|
|
66
|
+
"providers",
|
|
67
|
+
"!**/*.test.*"
|
|
68
|
+
],
|
|
69
|
+
"private": false,
|
|
70
|
+
"publishConfig": {
|
|
71
|
+
"access": "public"
|
|
72
|
+
},
|
|
73
|
+
"license": "MIT",
|
|
74
|
+
"dependencies": {
|
|
75
|
+
"@aws-sdk/client-s3": "^3.294.0",
|
|
76
|
+
"@aws-sdk/s3-request-presigner": "^3.294.0",
|
|
77
|
+
"@panva/hkdf": "^1.0.4",
|
|
78
|
+
"cookie": "^0.5.0",
|
|
79
|
+
"jose": "^4.13.1",
|
|
80
|
+
"uuid": "^9.0.0"
|
|
81
|
+
},
|
|
82
|
+
"peerDependencies": {
|
|
83
|
+
"zod": ">=3.0.0"
|
|
84
|
+
},
|
|
85
|
+
"devDependencies": {
|
|
86
|
+
"@types/cookie": "^0.5.1",
|
|
87
|
+
"@types/node": "^18.11.18",
|
|
88
|
+
"@types/uuid": "^9.0.1",
|
|
89
|
+
"next": "^13.4.9",
|
|
90
|
+
"react": "^18.2.0",
|
|
91
|
+
"react-dom": "^18.2.0",
|
|
92
|
+
"typescript": "^5.1.6",
|
|
93
|
+
"zod": "^3.21.4"
|
|
94
|
+
},
|
|
95
|
+
"gitHead": "bec47f77e223a231f5e04070aa8da6a609838e6b"
|
|
96
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../../dist/providers/aws';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('../../dist/providers/aws');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../../dist/providers/edgestore';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('../../dist/providers/edgestore');
|