@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,121 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var index = require('../../index-3999aae6.js');
|
|
6
|
+
|
|
7
|
+
const DEFAULT_BASE_URL = process.env.EDGE_STORE_BASE_URL ?? 'https://files.edge-store.com';
|
|
8
|
+
function EdgeStoreProvider(options) {
|
|
9
|
+
const { accessKey = process.env.EDGE_STORE_ACCESS_KEY, secretKey = process.env.EDGE_STORE_SECRET_KEY, baseUrl = process.env.EDGE_STORE_BASE_URL ?? DEFAULT_BASE_URL } = options ?? {};
|
|
10
|
+
if (!accessKey || !secretKey) {
|
|
11
|
+
throw new index.EdgeStoreCredentialsError();
|
|
12
|
+
}
|
|
13
|
+
const edgeStoreSdk = index.initEdgeStoreSdk({
|
|
14
|
+
accessKey,
|
|
15
|
+
secretKey
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
init: async ({ ctx, router })=>{
|
|
19
|
+
const token = await edgeStoreSdk.getToken({
|
|
20
|
+
ctx,
|
|
21
|
+
router
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
token
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
getBaseUrl () {
|
|
28
|
+
return baseUrl;
|
|
29
|
+
},
|
|
30
|
+
getFile: async ({ url })=>{
|
|
31
|
+
const { uploadedAt, ...rest } = await edgeStoreSdk.getFile({
|
|
32
|
+
url
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
uploadedAt: new Date(uploadedAt),
|
|
36
|
+
...rest
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
async requestUpload ({ bucketName, bucketType, fileInfo }) {
|
|
40
|
+
// multiplart upload if file is bigger than a certain size
|
|
41
|
+
const MULTIPART_THRESHOLD = 10 * 1024 * 1024; // 10MB
|
|
42
|
+
const CONCURRENCY = 3;
|
|
43
|
+
let partSize = 5 * 1024 * 1024; // 5MB
|
|
44
|
+
if (fileInfo.size > MULTIPART_THRESHOLD) {
|
|
45
|
+
let totalParts = Math.ceil(fileInfo.size / partSize);
|
|
46
|
+
if (totalParts > 10000) {
|
|
47
|
+
// the maximum number of parts is 10000
|
|
48
|
+
totalParts = 10000;
|
|
49
|
+
partSize = Math.ceil(fileInfo.size / totalParts);
|
|
50
|
+
}
|
|
51
|
+
const requestParts = totalParts > CONCURRENCY ? CONCURRENCY : totalParts;
|
|
52
|
+
const res = await edgeStoreSdk.requestUpload({
|
|
53
|
+
bucketName,
|
|
54
|
+
bucketType,
|
|
55
|
+
fileInfo,
|
|
56
|
+
multipart: {
|
|
57
|
+
parts: Array.from({
|
|
58
|
+
length: requestParts
|
|
59
|
+
}).map((_, index)=>index + 1)
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
const multipart = res.multipart ? {
|
|
63
|
+
uploadId: res.multipart.uploadId,
|
|
64
|
+
parts: res.multipart.parts.map((part)=>({
|
|
65
|
+
partNumber: part.partNumber,
|
|
66
|
+
uploadUrl: part.signedUrl
|
|
67
|
+
})),
|
|
68
|
+
partSize,
|
|
69
|
+
totalParts
|
|
70
|
+
} : undefined;
|
|
71
|
+
if (multipart) {
|
|
72
|
+
return {
|
|
73
|
+
accessUrl: res.accessUrl,
|
|
74
|
+
multipart
|
|
75
|
+
};
|
|
76
|
+
} else if (res.signedUrl) {
|
|
77
|
+
return {
|
|
78
|
+
accessUrl: res.accessUrl,
|
|
79
|
+
uploadUrl: res.signedUrl
|
|
80
|
+
};
|
|
81
|
+
} else {
|
|
82
|
+
throw new Error('Could not get upload url');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const res = await edgeStoreSdk.requestUpload({
|
|
86
|
+
bucketName,
|
|
87
|
+
bucketType,
|
|
88
|
+
fileInfo
|
|
89
|
+
});
|
|
90
|
+
if (res.signedUrl) {
|
|
91
|
+
return {
|
|
92
|
+
accessUrl: res.accessUrl,
|
|
93
|
+
uploadUrl: res.signedUrl
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
throw new Error('Could not get upload url');
|
|
97
|
+
},
|
|
98
|
+
requestUploadParts: async ({ multipart, path })=>{
|
|
99
|
+
const res = await edgeStoreSdk.requestUploadParts({
|
|
100
|
+
multipart,
|
|
101
|
+
key: path
|
|
102
|
+
});
|
|
103
|
+
return {
|
|
104
|
+
multipart: {
|
|
105
|
+
uploadId: res.multipart.uploadId,
|
|
106
|
+
parts: res.multipart.parts.map((part)=>({
|
|
107
|
+
partNumber: part.partNumber,
|
|
108
|
+
uploadUrl: part.signedUrl
|
|
109
|
+
}))
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
},
|
|
113
|
+
deleteFile: async ({ url })=>{
|
|
114
|
+
return await edgeStoreSdk.deleteFile({
|
|
115
|
+
url
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
exports.EdgeStoreProvider = EdgeStoreProvider;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { E as EdgeStoreCredentialsError, i as initEdgeStoreSdk } from '../../index-ca41982b.mjs';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_BASE_URL = process.env.EDGE_STORE_BASE_URL ?? 'https://files.edge-store.com';
|
|
4
|
+
function EdgeStoreProvider(options) {
|
|
5
|
+
const { accessKey = process.env.EDGE_STORE_ACCESS_KEY, secretKey = process.env.EDGE_STORE_SECRET_KEY, baseUrl = process.env.EDGE_STORE_BASE_URL ?? DEFAULT_BASE_URL } = options ?? {};
|
|
6
|
+
if (!accessKey || !secretKey) {
|
|
7
|
+
throw new EdgeStoreCredentialsError();
|
|
8
|
+
}
|
|
9
|
+
const edgeStoreSdk = initEdgeStoreSdk({
|
|
10
|
+
accessKey,
|
|
11
|
+
secretKey
|
|
12
|
+
});
|
|
13
|
+
return {
|
|
14
|
+
init: async ({ ctx, router })=>{
|
|
15
|
+
const token = await edgeStoreSdk.getToken({
|
|
16
|
+
ctx,
|
|
17
|
+
router
|
|
18
|
+
});
|
|
19
|
+
return {
|
|
20
|
+
token
|
|
21
|
+
};
|
|
22
|
+
},
|
|
23
|
+
getBaseUrl () {
|
|
24
|
+
return baseUrl;
|
|
25
|
+
},
|
|
26
|
+
getFile: async ({ url })=>{
|
|
27
|
+
const { uploadedAt, ...rest } = await edgeStoreSdk.getFile({
|
|
28
|
+
url
|
|
29
|
+
});
|
|
30
|
+
return {
|
|
31
|
+
uploadedAt: new Date(uploadedAt),
|
|
32
|
+
...rest
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
async requestUpload ({ bucketName, bucketType, fileInfo }) {
|
|
36
|
+
// multiplart upload if file is bigger than a certain size
|
|
37
|
+
const MULTIPART_THRESHOLD = 10 * 1024 * 1024; // 10MB
|
|
38
|
+
const CONCURRENCY = 3;
|
|
39
|
+
let partSize = 5 * 1024 * 1024; // 5MB
|
|
40
|
+
if (fileInfo.size > MULTIPART_THRESHOLD) {
|
|
41
|
+
let totalParts = Math.ceil(fileInfo.size / partSize);
|
|
42
|
+
if (totalParts > 10000) {
|
|
43
|
+
// the maximum number of parts is 10000
|
|
44
|
+
totalParts = 10000;
|
|
45
|
+
partSize = Math.ceil(fileInfo.size / totalParts);
|
|
46
|
+
}
|
|
47
|
+
const requestParts = totalParts > CONCURRENCY ? CONCURRENCY : totalParts;
|
|
48
|
+
const res = await edgeStoreSdk.requestUpload({
|
|
49
|
+
bucketName,
|
|
50
|
+
bucketType,
|
|
51
|
+
fileInfo,
|
|
52
|
+
multipart: {
|
|
53
|
+
parts: Array.from({
|
|
54
|
+
length: requestParts
|
|
55
|
+
}).map((_, index)=>index + 1)
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
const multipart = res.multipart ? {
|
|
59
|
+
uploadId: res.multipart.uploadId,
|
|
60
|
+
parts: res.multipart.parts.map((part)=>({
|
|
61
|
+
partNumber: part.partNumber,
|
|
62
|
+
uploadUrl: part.signedUrl
|
|
63
|
+
})),
|
|
64
|
+
partSize,
|
|
65
|
+
totalParts
|
|
66
|
+
} : undefined;
|
|
67
|
+
if (multipart) {
|
|
68
|
+
return {
|
|
69
|
+
accessUrl: res.accessUrl,
|
|
70
|
+
multipart
|
|
71
|
+
};
|
|
72
|
+
} else if (res.signedUrl) {
|
|
73
|
+
return {
|
|
74
|
+
accessUrl: res.accessUrl,
|
|
75
|
+
uploadUrl: res.signedUrl
|
|
76
|
+
};
|
|
77
|
+
} else {
|
|
78
|
+
throw new Error('Could not get upload url');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const res = await edgeStoreSdk.requestUpload({
|
|
82
|
+
bucketName,
|
|
83
|
+
bucketType,
|
|
84
|
+
fileInfo
|
|
85
|
+
});
|
|
86
|
+
if (res.signedUrl) {
|
|
87
|
+
return {
|
|
88
|
+
accessUrl: res.accessUrl,
|
|
89
|
+
uploadUrl: res.signedUrl
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
throw new Error('Could not get upload url');
|
|
93
|
+
},
|
|
94
|
+
requestUploadParts: async ({ multipart, path })=>{
|
|
95
|
+
const res = await edgeStoreSdk.requestUploadParts({
|
|
96
|
+
multipart,
|
|
97
|
+
key: path
|
|
98
|
+
});
|
|
99
|
+
return {
|
|
100
|
+
multipart: {
|
|
101
|
+
uploadId: res.multipart.uploadId,
|
|
102
|
+
parts: res.multipart.parts.map((part)=>({
|
|
103
|
+
partNumber: part.partNumber,
|
|
104
|
+
uploadUrl: part.signedUrl
|
|
105
|
+
}))
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
},
|
|
109
|
+
deleteFile: async ({ url })=>{
|
|
110
|
+
return await edgeStoreSdk.deleteFile({
|
|
111
|
+
url
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export { EdgeStoreProvider };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { AnyBuilder, EdgeStoreRouter } from '../core/internals/bucketBuilder';
|
|
2
|
+
import { MaybePromise } from '../types';
|
|
3
|
+
export type InitParams = {
|
|
4
|
+
ctx: any;
|
|
5
|
+
router: EdgeStoreRouter<any>;
|
|
6
|
+
};
|
|
7
|
+
export type InitRes = {
|
|
8
|
+
token?: string;
|
|
9
|
+
};
|
|
10
|
+
export type GetFileParams = {
|
|
11
|
+
url: string;
|
|
12
|
+
};
|
|
13
|
+
export type GetFileRes = {
|
|
14
|
+
url: string;
|
|
15
|
+
size: number;
|
|
16
|
+
uploadedAt: Date;
|
|
17
|
+
path: {
|
|
18
|
+
[key: string]: string;
|
|
19
|
+
};
|
|
20
|
+
metadata: {
|
|
21
|
+
[key: string]: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export type RequestUploadParams = {
|
|
25
|
+
multipart?: {
|
|
26
|
+
uploadId?: string;
|
|
27
|
+
parts: number[];
|
|
28
|
+
};
|
|
29
|
+
bucketName: string;
|
|
30
|
+
bucketType: string;
|
|
31
|
+
fileInfo: {
|
|
32
|
+
size: number;
|
|
33
|
+
extension: string;
|
|
34
|
+
isPublic: boolean;
|
|
35
|
+
path: {
|
|
36
|
+
key: string;
|
|
37
|
+
value: string;
|
|
38
|
+
}[];
|
|
39
|
+
metadata?: {
|
|
40
|
+
[key: string]: string;
|
|
41
|
+
};
|
|
42
|
+
replaceTargetUrl?: string;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
export type RequestUploadPartsParams = {
|
|
46
|
+
multipart: {
|
|
47
|
+
uploadId: string;
|
|
48
|
+
parts: number[];
|
|
49
|
+
};
|
|
50
|
+
path: string;
|
|
51
|
+
};
|
|
52
|
+
export type RequestUploadPartsRes = {
|
|
53
|
+
multipart: {
|
|
54
|
+
uploadId: string;
|
|
55
|
+
parts: {
|
|
56
|
+
partNumber: number;
|
|
57
|
+
uploadUrl: string;
|
|
58
|
+
}[];
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
export type RequestUploadRes = {
|
|
62
|
+
uploadUrl: string;
|
|
63
|
+
accessUrl: string;
|
|
64
|
+
} | {
|
|
65
|
+
multipart: {
|
|
66
|
+
uploadId: string;
|
|
67
|
+
partSize: number;
|
|
68
|
+
totalParts: number;
|
|
69
|
+
parts: {
|
|
70
|
+
partNumber: number;
|
|
71
|
+
uploadUrl: string;
|
|
72
|
+
}[];
|
|
73
|
+
};
|
|
74
|
+
accessUrl: string;
|
|
75
|
+
};
|
|
76
|
+
export type DeleteFileParams = {
|
|
77
|
+
bucket: AnyBuilder;
|
|
78
|
+
url: string;
|
|
79
|
+
};
|
|
80
|
+
export type DeleteFileRes = {
|
|
81
|
+
success: boolean;
|
|
82
|
+
};
|
|
83
|
+
export type Provider = {
|
|
84
|
+
init: (params: InitParams) => MaybePromise<InitRes>;
|
|
85
|
+
getBaseUrl: () => MaybePromise<string>;
|
|
86
|
+
getFile: (params: GetFileParams) => MaybePromise<GetFileRes>;
|
|
87
|
+
requestUpload: (params: RequestUploadParams) => MaybePromise<RequestUploadRes>;
|
|
88
|
+
requestUploadParts: (params: RequestUploadPartsParams) => MaybePromise<RequestUploadPartsRes>;
|
|
89
|
+
deleteFile: (params: DeleteFileParams) => MaybePromise<DeleteFileRes>;
|
|
90
|
+
};
|
|
91
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,GAAG,CAAC;IACT,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,IAAI,CAAC;IACjB,IAAI,EAAE;QACJ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;KACvB,CAAC;IACF,QAAQ,EAAE;QACR,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;KACvB,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,CAAC,EAAE;QACV,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,OAAO,CAAC;QAClB,IAAI,EAAE;YACJ,GAAG,EAAE,MAAM,CAAC;YACZ,KAAK,EAAE,MAAM,CAAC;SACf,EAAE,CAAC;QACJ,QAAQ,CAAC,EAAE;YACT,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;SACvB,CAAC;QACF,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE;QACT,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;IACF,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE;QACT,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE;YACL,UAAU,EAAE,MAAM,CAAC;YACnB,SAAS,EAAE,MAAM,CAAC;SACnB,EAAE,CAAC;KACL,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,gBAAgB,GACxB;IACE,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB,GACD;IACE,SAAS,EAAE;QACT,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE;YACL,UAAU,EAAE,MAAM,CAAC;YACnB,SAAS,EAAE,MAAM,CAAC;SACnB,EAAE,CAAC;KACL,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEN,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,UAAU,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,YAAY,CAAC,OAAO,CAAC,CAAC;IACpD,UAAU,EAAE,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,YAAY,CAAC,UAAU,CAAC,CAAC;IAC7D,aAAa,EAAE,CACb,MAAM,EAAE,mBAAmB,KACxB,YAAY,CAAC,gBAAgB,CAAC,CAAC;IACpC,kBAAkB,EAAE,CAClB,MAAM,EAAE,wBAAwB,KAC7B,YAAY,CAAC,qBAAqB,CAAC,CAAC;IACzC,UAAU,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,YAAY,CAAC,aAAa,CAAC,CAAC;CACvE,CAAC"}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { hkdf } from '@panva/hkdf';
|
|
2
|
+
import { serialize } from 'cookie';
|
|
3
|
+
import { EncryptJWT, jwtDecrypt } from 'jose';
|
|
4
|
+
import { v4 } from 'uuid';
|
|
5
|
+
import { _ } from '@swc/helpers/_/_define_property';
|
|
6
|
+
|
|
7
|
+
const EDGE_STORE_ERROR_CODES = {
|
|
8
|
+
BAD_REQUEST: 400,
|
|
9
|
+
UNAUTHORIZED: 401
|
|
10
|
+
};
|
|
11
|
+
class EdgeStoreError extends Error {
|
|
12
|
+
constructor(opts){
|
|
13
|
+
super(opts.message);
|
|
14
|
+
_(this, "cause", void 0);
|
|
15
|
+
_(this, "code", void 0);
|
|
16
|
+
this.name = 'EdgeStoreError';
|
|
17
|
+
this.code = opts.code;
|
|
18
|
+
this.cause = opts.cause;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const IMAGE_MIME_TYPES = [
|
|
23
|
+
'image/jpeg',
|
|
24
|
+
'image/png',
|
|
25
|
+
'image/gif',
|
|
26
|
+
'image/webp',
|
|
27
|
+
'image/svg+xml',
|
|
28
|
+
'image/tiff',
|
|
29
|
+
'image/bmp',
|
|
30
|
+
'image/x-icon'
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
// TODO: change it to 1 hour when we have a way to refresh the token
|
|
34
|
+
const DEFAULT_MAX_AGE = 30 * 24 * 60 * 60; // 30 days
|
|
35
|
+
async function init(params) {
|
|
36
|
+
const { ctx, provider, router } = params;
|
|
37
|
+
const ctxToken = await encryptJWT(ctx);
|
|
38
|
+
const { token } = await provider.init({
|
|
39
|
+
ctx,
|
|
40
|
+
router: router
|
|
41
|
+
});
|
|
42
|
+
const newCookies = [
|
|
43
|
+
serialize('edgestore-ctx', ctxToken, {
|
|
44
|
+
path: '/',
|
|
45
|
+
maxAge: DEFAULT_MAX_AGE
|
|
46
|
+
})
|
|
47
|
+
];
|
|
48
|
+
if (token) {
|
|
49
|
+
newCookies.push(serialize('edgestore-token', token, {
|
|
50
|
+
path: '/',
|
|
51
|
+
maxAge: DEFAULT_MAX_AGE
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
const baseUrl = provider.getBaseUrl();
|
|
55
|
+
return {
|
|
56
|
+
newCookies,
|
|
57
|
+
token,
|
|
58
|
+
baseUrl
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async function requestUpload(params) {
|
|
62
|
+
const { provider, router, ctxToken, body: { bucketName, input, fileInfo } } = params;
|
|
63
|
+
if (!ctxToken) {
|
|
64
|
+
throw new EdgeStoreError({
|
|
65
|
+
message: 'Missing edgestore-ctx cookie',
|
|
66
|
+
code: 'UNAUTHORIZED'
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const ctx = await getContext(ctxToken);
|
|
70
|
+
const bucket = router.buckets[bucketName];
|
|
71
|
+
if (!bucket) {
|
|
72
|
+
throw new Error(`Bucket ${bucketName} not found`);
|
|
73
|
+
}
|
|
74
|
+
if (bucket._def.beforeUpload) {
|
|
75
|
+
const canUpload = await bucket._def.beforeUpload?.({
|
|
76
|
+
ctx,
|
|
77
|
+
input,
|
|
78
|
+
fileInfo: {
|
|
79
|
+
size: fileInfo.size,
|
|
80
|
+
type: fileInfo.type,
|
|
81
|
+
extension: fileInfo.extension,
|
|
82
|
+
replaceTargetUrl: fileInfo.replaceTargetUrl
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
if (!canUpload) {
|
|
86
|
+
throw new Error('Upload not allowed');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (bucket._def.type === 'IMAGE') {
|
|
90
|
+
if (!IMAGE_MIME_TYPES.includes(fileInfo.type)) {
|
|
91
|
+
throw new EdgeStoreError({
|
|
92
|
+
code: 'BAD_REQUEST',
|
|
93
|
+
message: 'Only images are allowed in this bucket'
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const path = buildPath({
|
|
98
|
+
fileInfo,
|
|
99
|
+
bucket,
|
|
100
|
+
pathAttrs: {
|
|
101
|
+
ctx,
|
|
102
|
+
input
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
const metadata = await bucket._def.metadata?.({
|
|
106
|
+
ctx,
|
|
107
|
+
input
|
|
108
|
+
});
|
|
109
|
+
const isPublic = bucket._def.accessControl === undefined;
|
|
110
|
+
const requestUploadRes = await provider.requestUpload({
|
|
111
|
+
bucketName,
|
|
112
|
+
bucketType: bucket._def.type,
|
|
113
|
+
fileInfo: {
|
|
114
|
+
...fileInfo,
|
|
115
|
+
path,
|
|
116
|
+
isPublic,
|
|
117
|
+
metadata
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
return {
|
|
121
|
+
...requestUploadRes,
|
|
122
|
+
size: fileInfo.size,
|
|
123
|
+
uploadedAt: new Date().toISOString(),
|
|
124
|
+
path,
|
|
125
|
+
metadata
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
async function requestUploadParts(params) {
|
|
129
|
+
const { provider, router, ctxToken, body: { multipart, path } } = params;
|
|
130
|
+
if (!ctxToken) {
|
|
131
|
+
throw new EdgeStoreError({
|
|
132
|
+
message: 'Missing edgestore-ctx cookie',
|
|
133
|
+
code: 'UNAUTHORIZED'
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
await getContext(ctxToken); // just to check if the token is valid
|
|
137
|
+
const bucket = router.buckets[multipart.uploadId];
|
|
138
|
+
if (!bucket) {
|
|
139
|
+
throw new Error(`Bucket ${multipart.uploadId} not found`);
|
|
140
|
+
}
|
|
141
|
+
return await provider.requestUploadParts({
|
|
142
|
+
multipart,
|
|
143
|
+
path
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
async function deleteFile(params) {
|
|
147
|
+
const { provider, router, ctxToken, body: { bucketName, url } } = params;
|
|
148
|
+
if (!ctxToken) {
|
|
149
|
+
throw new EdgeStoreError({
|
|
150
|
+
message: 'Missing edgestore-ctx cookie',
|
|
151
|
+
code: 'UNAUTHORIZED'
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
const ctx = await getContext(ctxToken);
|
|
155
|
+
const bucket = router.buckets[bucketName];
|
|
156
|
+
if (!bucket) {
|
|
157
|
+
throw new Error(`Bucket ${bucketName} not found`);
|
|
158
|
+
}
|
|
159
|
+
if (!bucket._def.beforeDelete) {
|
|
160
|
+
throw new Error('You need to define beforeDelete if you want to delete files directly from the frontend.');
|
|
161
|
+
}
|
|
162
|
+
const file = await provider.getFile({
|
|
163
|
+
url
|
|
164
|
+
});
|
|
165
|
+
const canDelete = await bucket._def.beforeDelete({
|
|
166
|
+
ctx,
|
|
167
|
+
file
|
|
168
|
+
});
|
|
169
|
+
if (!canDelete) {
|
|
170
|
+
throw new Error('Delete not allowed');
|
|
171
|
+
}
|
|
172
|
+
await provider.deleteFile({
|
|
173
|
+
bucket,
|
|
174
|
+
url
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
async function encryptJWT(ctx) {
|
|
178
|
+
const secret = process.env.EDGE_STORE_JWT_SECRET ?? process.env.EDGE_STORE_SECRET_KEY;
|
|
179
|
+
if (!secret) {
|
|
180
|
+
throw new Error('EDGE_STORE_JWT_SECRET or EDGE_STORE_SECRET_KEY is not defined');
|
|
181
|
+
}
|
|
182
|
+
const encryptionSecret = await getDerivedEncryptionKey(secret);
|
|
183
|
+
return await new EncryptJWT(ctx).setProtectedHeader({
|
|
184
|
+
alg: 'dir',
|
|
185
|
+
enc: 'A256GCM'
|
|
186
|
+
}).setIssuedAt().setExpirationTime(Date.now() / 1000 + DEFAULT_MAX_AGE).setJti(v4()).encrypt(encryptionSecret);
|
|
187
|
+
}
|
|
188
|
+
async function decryptJWT(token) {
|
|
189
|
+
const secret = process.env.EDGE_STORE_JWT_SECRET ?? process.env.EDGE_STORE_SECRET_KEY;
|
|
190
|
+
if (!secret) {
|
|
191
|
+
throw new Error('EDGE_STORE_JWT_SECRET or EDGE_STORE_SECRET_KEY is not set');
|
|
192
|
+
}
|
|
193
|
+
const encryptionSecret = await getDerivedEncryptionKey(secret);
|
|
194
|
+
const { payload } = await jwtDecrypt(token, encryptionSecret, {
|
|
195
|
+
clockTolerance: 15
|
|
196
|
+
});
|
|
197
|
+
return payload;
|
|
198
|
+
}
|
|
199
|
+
async function getDerivedEncryptionKey(secret) {
|
|
200
|
+
return await hkdf('sha256', secret, '', 'Edge Store Generated Encryption Key', 32);
|
|
201
|
+
}
|
|
202
|
+
function buildPath(params) {
|
|
203
|
+
const { bucket } = params;
|
|
204
|
+
const pathParams = bucket._def.path;
|
|
205
|
+
const path = pathParams.map((param)=>{
|
|
206
|
+
const paramEntries = Object.entries(param);
|
|
207
|
+
if (paramEntries[0] === undefined) {
|
|
208
|
+
throw new Error('Missing path param');
|
|
209
|
+
}
|
|
210
|
+
const [key, value] = paramEntries[0];
|
|
211
|
+
// this is a string like: "ctx.xxx" or "input.yyy.zzz"
|
|
212
|
+
const currParamVal = value().split('.').reduce((acc2, key)=>{
|
|
213
|
+
if (acc2[key] === undefined) {
|
|
214
|
+
throw new Error(`Missing key ${key} in ${JSON.stringify(acc2)}`);
|
|
215
|
+
}
|
|
216
|
+
return acc2[key];
|
|
217
|
+
}, params.pathAttrs);
|
|
218
|
+
return {
|
|
219
|
+
key,
|
|
220
|
+
value: currParamVal
|
|
221
|
+
};
|
|
222
|
+
});
|
|
223
|
+
return path;
|
|
224
|
+
}
|
|
225
|
+
async function getContext(token) {
|
|
226
|
+
if (!token) {
|
|
227
|
+
throw new Error('No token');
|
|
228
|
+
}
|
|
229
|
+
return await decryptJWT(token);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export { EdgeStoreError as E, requestUploadParts as a, EDGE_STORE_ERROR_CODES as b, deleteFile as d, init as i, requestUpload as r };
|