@edgestore/server 0.1.1 → 0.1.3-alpha.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.
Files changed (55) hide show
  1. package/README.md +1 -1
  2. package/adapters/index.d.ts +1 -0
  3. package/adapters/index.js +1 -0
  4. package/dist/adapters/index.d.ts +2 -0
  5. package/dist/adapters/index.d.ts.map +1 -0
  6. package/dist/adapters/index.js +2 -0
  7. package/dist/adapters/index.mjs +1 -0
  8. package/dist/adapters/next/app/index.d.ts.map +1 -1
  9. package/dist/adapters/next/app/index.js +28 -5
  10. package/dist/adapters/next/app/index.mjs +28 -5
  11. package/dist/adapters/next/pages/index.d.ts.map +1 -1
  12. package/dist/adapters/next/pages/index.js +18 -2
  13. package/dist/adapters/next/pages/index.mjs +18 -2
  14. package/dist/adapters/shared.d.ts +33 -0
  15. package/dist/adapters/shared.d.ts.map +1 -1
  16. package/dist/core/client/index.d.ts +8 -0
  17. package/dist/core/client/index.d.ts.map +1 -1
  18. package/dist/core/index.js +5 -4
  19. package/dist/core/index.mjs +6 -5
  20. package/dist/core/internals/bucketBuilder.d.ts +1 -0
  21. package/dist/core/internals/bucketBuilder.d.ts.map +1 -1
  22. package/dist/core/sdk/index.d.ts +41 -0
  23. package/dist/core/sdk/index.d.ts.map +1 -1
  24. package/dist/{index-579b8015.mjs → index-30a3741e.mjs} +43 -2
  25. package/dist/{index-62d969e5.js → index-50ab9e08.js} +43 -2
  26. package/dist/{index-0a168903.js → index-f33a00fb.js} +41 -0
  27. package/dist/providers/aws/index.d.ts.map +1 -1
  28. package/dist/providers/aws/index.js +6 -0
  29. package/dist/providers/aws/index.mjs +6 -0
  30. package/dist/providers/edgestore/index.d.ts.map +1 -1
  31. package/dist/providers/edgestore/index.js +24 -10
  32. package/dist/providers/edgestore/index.mjs +24 -10
  33. package/dist/providers/index.d.ts +1 -2
  34. package/dist/providers/index.d.ts.map +1 -1
  35. package/dist/providers/index.js +2 -0
  36. package/dist/providers/index.mjs +1 -0
  37. package/dist/providers/types.d.ts +24 -0
  38. package/dist/providers/types.d.ts.map +1 -1
  39. package/dist/{shared-2a9c8307.mjs → shared-7fc08e14.mjs} +40 -2
  40. package/dist/{shared-ae739a04.js → shared-a5b84d0b.js} +41 -1
  41. package/dist/{shared-fac1b0a0.js → shared-a86ccc68.js} +39 -1
  42. package/package.json +13 -3
  43. package/providers/index.d.ts +1 -0
  44. package/providers/index.js +1 -0
  45. package/src/adapters/index.ts +6 -0
  46. package/src/adapters/next/app/index.ts +31 -2
  47. package/src/adapters/next/pages/index.ts +20 -0
  48. package/src/adapters/shared.ts +85 -0
  49. package/src/core/client/index.ts +9 -3
  50. package/src/core/internals/bucketBuilder.ts +1 -0
  51. package/src/core/sdk/index.ts +81 -0
  52. package/src/providers/aws/index.ts +6 -0
  53. package/src/providers/edgestore/index.ts +21 -8
  54. package/src/providers/index.ts +1 -2
  55. package/src/providers/types.ts +30 -0
@@ -0,0 +1,6 @@
1
+ export type {
2
+ InitRes,
3
+ RequestUploadRes,
4
+ RequestUploadPartsRes,
5
+ DeleteFileRes,
6
+ } from './shared';
@@ -7,10 +7,14 @@ import { EdgeStoreProvider } from '../../../providers/edgestore';
7
7
  import { type Provider } from '../../../providers/types';
8
8
  import { type MaybePromise } from '../../../types';
9
9
  import {
10
+ completeMultipartUpload,
11
+ confirmUpload,
10
12
  deleteFile,
11
13
  init,
12
14
  requestUpload,
13
15
  requestUploadParts,
16
+ type CompleteMultipartUploadBody,
17
+ type ConfirmUploadBody,
14
18
  type DeleteFileBody,
15
19
  type RequestUploadBody,
16
20
  type RequestUploadPartsParams,
@@ -45,7 +49,7 @@ export function createEdgeStoreNextHandler<TCtx>(config: Config<TCtx>) {
45
49
  provider,
46
50
  router: config.router,
47
51
  });
48
- return new Response(
52
+ const res = new Response(
49
53
  JSON.stringify({
50
54
  token,
51
55
  baseUrl,
@@ -54,10 +58,13 @@ export function createEdgeStoreNextHandler<TCtx>(config: Config<TCtx>) {
54
58
  status: 200,
55
59
  headers: {
56
60
  'Content-Type': 'application/json',
57
- 'Set-Cookie': newCookies.join('; '),
58
61
  },
59
62
  },
60
63
  );
64
+ for (const cookie of newCookies) {
65
+ res.headers.append('Set-Cookie', cookie);
66
+ }
67
+ return res;
61
68
  } else if (req.nextUrl.pathname === '/api/edgestore/request-upload') {
62
69
  const res = await requestUpload({
63
70
  provider,
@@ -86,6 +93,28 @@ export function createEdgeStoreNextHandler<TCtx>(config: Config<TCtx>) {
86
93
  'Content-Type': 'application/json',
87
94
  },
88
95
  });
96
+ } else if (
97
+ req.nextUrl.pathname === '/api/edgestore/complete-multipart-upload'
98
+ ) {
99
+ await completeMultipartUpload({
100
+ provider,
101
+ router: config.router,
102
+ body: (await req.json()) as CompleteMultipartUploadBody,
103
+ ctxToken: req.cookies.get('edgestore-ctx')?.value,
104
+ });
105
+ return new Response(null, {
106
+ status: 200,
107
+ });
108
+ } else if (req.nextUrl.pathname === '/api/edgestore/confirm-upload') {
109
+ await confirmUpload({
110
+ provider,
111
+ router: config.router,
112
+ body: (await req.json()) as ConfirmUploadBody,
113
+ ctxToken: req.cookies.get('edgestore-ctx')?.value,
114
+ });
115
+ return new Response(null, {
116
+ status: 200,
117
+ });
89
118
  } else if (req.nextUrl.pathname === '/api/edgestore/delete-file') {
90
119
  await deleteFile({
91
120
  provider,
@@ -7,10 +7,14 @@ import { EdgeStoreProvider } from '../../../providers/edgestore';
7
7
  import { type Provider } from '../../../providers/types';
8
8
  import { type MaybePromise } from '../../../types';
9
9
  import {
10
+ completeMultipartUpload,
11
+ confirmUpload,
10
12
  deleteFile,
11
13
  init,
12
14
  requestUpload,
13
15
  requestUploadParts,
16
+ type CompleteMultipartUploadBody,
17
+ type ConfirmUploadBody,
14
18
  type DeleteFileBody,
15
19
  type RequestUploadBody,
16
20
  type RequestUploadPartsParams,
@@ -69,6 +73,22 @@ export function createEdgeStoreNextHandler<TCtx>(config: Config<TCtx>) {
69
73
  ctxToken: req.cookies['edgestore-ctx'],
70
74
  }),
71
75
  );
76
+ } else if (req.url === '/api/edgestore/complete-multipart-upload') {
77
+ await completeMultipartUpload({
78
+ provider,
79
+ router: config.router,
80
+ body: req.body as CompleteMultipartUploadBody,
81
+ ctxToken: req.cookies['edgestore-ctx'],
82
+ });
83
+ res.status(200).end();
84
+ } else if (req.url === '/api/edgestore/confirm-upload') {
85
+ await confirmUpload({
86
+ provider,
87
+ router: config.router,
88
+ body: req.body as ConfirmUploadBody,
89
+ ctxToken: req.cookies['edgestore-ctx'],
90
+ });
91
+ res.status(200).end();
72
92
  } else if (req.url === '/api/edgestore/delete-file') {
73
93
  await deleteFile({
74
94
  provider,
@@ -56,6 +56,7 @@ export type RequestUploadBody = {
56
56
  extension: string;
57
57
  fileName?: string;
58
58
  replaceTargetUrl?: string;
59
+ temporary: boolean;
59
60
  };
60
61
  };
61
62
 
@@ -93,6 +94,7 @@ export async function requestUpload<TCtx>(params: {
93
94
  fileName: fileInfo.fileName,
94
95
  extension: fileInfo.extension,
95
96
  replaceTargetUrl: fileInfo.replaceTargetUrl,
97
+ temporary: fileInfo.temporary,
96
98
  },
97
99
  });
98
100
  if (!canUpload) {
@@ -206,6 +208,82 @@ export async function requestUploadParts<TCtx>(params: {
206
208
  });
207
209
  }
208
210
 
211
+ export type CompleteMultipartUploadBody = {
212
+ bucketName: string;
213
+ uploadId: string;
214
+ key: string;
215
+ parts: {
216
+ partNumber: number;
217
+ eTag: string;
218
+ }[];
219
+ };
220
+
221
+ export async function completeMultipartUpload<TCtx>(params: {
222
+ provider: Provider;
223
+ router: EdgeStoreRouter<TCtx>;
224
+ ctxToken: string | undefined;
225
+ body: CompleteMultipartUploadBody;
226
+ }) {
227
+ const {
228
+ provider,
229
+ router,
230
+ ctxToken,
231
+ body: { bucketName, uploadId, key, parts },
232
+ } = params;
233
+ if (!ctxToken) {
234
+ throw new EdgeStoreError({
235
+ message: 'Missing edgestore-ctx cookie',
236
+ code: 'UNAUTHORIZED',
237
+ });
238
+ }
239
+ await getContext(ctxToken); // just to check if the token is valid
240
+ const bucket = router.buckets[bucketName];
241
+ if (!bucket) {
242
+ throw new Error(`Bucket ${bucketName} not found`);
243
+ }
244
+ return await provider.completeMultipartUpload({
245
+ uploadId,
246
+ key,
247
+ parts,
248
+ });
249
+ }
250
+
251
+ export type ConfirmUploadBody = {
252
+ bucketName: string;
253
+ url: string;
254
+ };
255
+
256
+ export async function confirmUpload<TCtx>(params: {
257
+ provider: Provider;
258
+ router: EdgeStoreRouter<TCtx>;
259
+ ctxToken: string | undefined;
260
+ body: ConfirmUploadBody;
261
+ }) {
262
+ const {
263
+ provider,
264
+ router,
265
+ ctxToken,
266
+ body: { bucketName, url },
267
+ } = params;
268
+
269
+ if (!ctxToken) {
270
+ throw new EdgeStoreError({
271
+ message: 'Missing edgestore-ctx cookie',
272
+ code: 'UNAUTHORIZED',
273
+ });
274
+ }
275
+ await getContext(ctxToken); // just to check if the token is valid
276
+ const bucket = router.buckets[bucketName];
277
+ if (!bucket) {
278
+ throw new Error(`Bucket ${bucketName} not found`);
279
+ }
280
+
281
+ await provider.confirmUpload({
282
+ bucket,
283
+ url,
284
+ });
285
+ }
286
+
209
287
  export type DeleteFileBody = {
210
288
  bucketName: string;
211
289
  url: string;
@@ -339,3 +417,10 @@ async function getContext(token?: string) {
339
417
  }
340
418
  return await decryptJWT(token);
341
419
  }
420
+
421
+ export type InitRes = Awaited<ReturnType<typeof init>>;
422
+ export type RequestUploadRes = Awaited<ReturnType<typeof requestUpload>>;
423
+ export type RequestUploadPartsRes = Awaited<
424
+ ReturnType<typeof requestUploadParts>
425
+ >;
426
+ export type DeleteFileRes = Awaited<ReturnType<typeof deleteFile>>;
@@ -77,6 +77,10 @@ type EdgeStoreClient<TRouter extends AnyRouter> = {
77
77
  // uploadUrl: string;
78
78
  // accessUrl: string;
79
79
  // }>;
80
+ /**
81
+ * Confirm a temporary file upload.
82
+ */
83
+ confirmUpload: (params: { url: string }) => Promise<{ success: boolean }>;
80
84
  /**
81
85
  * Programmatically delete a file.
82
86
  */
@@ -168,10 +172,12 @@ export function initEdgeStoreClient<TRouter extends AnyRouter>(config: {
168
172
  // });
169
173
  // },
170
174
 
175
+ async confirmUpload(params) {
176
+ return await sdk.confirmUpload(params);
177
+ },
178
+
171
179
  async deleteFile(params) {
172
- return await sdk.deleteFile({
173
- ...params,
174
- });
180
+ return await sdk.deleteFile(params);
175
181
  },
176
182
 
177
183
  async listFiles(params) {
@@ -117,6 +117,7 @@ type FileInfo = {
117
117
  extension: string;
118
118
  fileName?: string;
119
119
  replaceTargetUrl?: string;
120
+ temporary: boolean;
120
121
  };
121
122
 
122
123
  type BeforeUploadFn<TCtx, TDef extends AnyDef> = (params: {
@@ -17,6 +17,7 @@ type FileInfoForUpload = {
17
17
  metadata: AnyMetadata;
18
18
  fileName?: string;
19
19
  replaceTargetUrl?: string;
20
+ temporary: boolean;
20
21
  };
21
22
 
22
23
  export type SimpleOperator =
@@ -162,6 +163,7 @@ export const edgeStoreRawSdk = {
162
163
  }) {
163
164
  const res = await makeRequest<{
164
165
  multipart?: {
166
+ key: string;
165
167
  uploadId: string;
166
168
  parts: {
167
169
  partNumber: number;
@@ -170,6 +172,8 @@ export const edgeStoreRawSdk = {
170
172
  };
171
173
  signedUrl?: string;
172
174
  url: string;
175
+ path: string;
176
+ thumbnailUrl: string | null;
173
177
  }>({
174
178
  path: '/request-upload',
175
179
  accessKey,
@@ -186,12 +190,15 @@ export const edgeStoreRawSdk = {
186
190
  metadata: fileInfo.metadata,
187
191
  fileName: fileInfo.fileName,
188
192
  replaceTargetUrl: fileInfo.replaceTargetUrl,
193
+ isTemporary: fileInfo.temporary,
189
194
  },
190
195
  });
191
196
  return {
192
197
  multipart: res.multipart,
193
198
  signedUrl: res.signedUrl,
194
199
  accessUrl: res.url,
200
+ path: res.path,
201
+ thumbnailUrl: res.thumbnailUrl,
195
202
  };
196
203
  },
197
204
 
@@ -231,6 +238,53 @@ export const edgeStoreRawSdk = {
231
238
  };
232
239
  },
233
240
 
241
+ async completeMultipartUpload({
242
+ accessKey,
243
+ secretKey,
244
+ uploadId,
245
+ key,
246
+ parts,
247
+ }: {
248
+ accessKey: string;
249
+ secretKey: string;
250
+ uploadId: string;
251
+ key: string;
252
+ parts: {
253
+ partNumber: number;
254
+ eTag: string;
255
+ }[];
256
+ }) {
257
+ return await makeRequest<{ success: boolean }>({
258
+ path: '/complete-multipart-upload',
259
+ accessKey,
260
+ secretKey,
261
+ body: {
262
+ uploadId,
263
+ key,
264
+ parts,
265
+ },
266
+ });
267
+ },
268
+
269
+ async confirmUpload({
270
+ accessKey,
271
+ secretKey,
272
+ url,
273
+ }: {
274
+ accessKey: string;
275
+ secretKey: string;
276
+ url: string;
277
+ }) {
278
+ return await makeRequest<{ success: boolean }>({
279
+ path: '/confirm-upload',
280
+ accessKey,
281
+ secretKey,
282
+ body: {
283
+ url,
284
+ },
285
+ });
286
+ },
287
+
234
288
  async deleteFile({
235
289
  accessKey,
236
290
  secretKey,
@@ -359,6 +413,33 @@ export function initEdgeStoreSdk(params: {
359
413
  multipart,
360
414
  });
361
415
  },
416
+ async completeMultipartUpload({
417
+ uploadId,
418
+ key,
419
+ parts,
420
+ }: {
421
+ uploadId: string;
422
+ key: string;
423
+ parts: {
424
+ partNumber: number;
425
+ eTag: string;
426
+ }[];
427
+ }) {
428
+ return await edgeStoreRawSdk.completeMultipartUpload({
429
+ accessKey,
430
+ secretKey,
431
+ uploadId,
432
+ key,
433
+ parts,
434
+ });
435
+ },
436
+ async confirmUpload({ url }: { url: string }) {
437
+ return await edgeStoreRawSdk.confirmUpload({
438
+ accessKey,
439
+ secretKey,
440
+ url,
441
+ });
442
+ },
362
443
  async deleteFile({ url }: { url: string }) {
363
444
  return await edgeStoreRawSdk.deleteFile({
364
445
  accessKey,
@@ -121,6 +121,12 @@ export function AWSProvider(options?: AWSProviderOptions): Provider {
121
121
  async requestUploadParts() {
122
122
  throw new Error('Not implemented');
123
123
  },
124
+ async completeMultipartUpload() {
125
+ throw new Error('Not implemented');
126
+ },
127
+ async confirmUpload() {
128
+ throw new Error('Not implemented');
129
+ },
124
130
  async deleteFile({ url }) {
125
131
  const path = url.replace(`${baseUrl}/`, '');
126
132
  await s3Client.send(
@@ -66,31 +66,29 @@ export function EdgeStoreProvider(
66
66
  bucketType,
67
67
  fileInfo,
68
68
  }): Promise<RequestUploadRes> {
69
- // multiplart upload if file is bigger than a certain size
69
+ // multipart upload if file is bigger than a certain size
70
70
  const MULTIPART_THRESHOLD = 10 * 1024 * 1024; // 10MB
71
- const CONCURRENCY = 3;
72
71
  let partSize = 5 * 1024 * 1024; // 5MB
73
72
  if (fileInfo.size > MULTIPART_THRESHOLD) {
74
73
  let totalParts = Math.ceil(fileInfo.size / partSize);
75
- if (totalParts > 10000) {
76
- // the maximum number of parts is 10000
77
- totalParts = 10000;
74
+ if (totalParts > 1000) {
75
+ // the maximum number of parts is 1000
76
+ totalParts = 1000;
78
77
  partSize = Math.ceil(fileInfo.size / totalParts);
79
78
  }
80
- const requestParts =
81
- totalParts > CONCURRENCY ? CONCURRENCY : totalParts;
82
79
  const res = await edgeStoreSdk.requestUpload({
83
80
  bucketName,
84
81
  bucketType,
85
82
  fileInfo,
86
83
  multipart: {
87
- parts: Array.from({ length: requestParts }).map(
84
+ parts: Array.from({ length: totalParts }).map(
88
85
  (_, index) => index + 1,
89
86
  ),
90
87
  },
91
88
  });
92
89
  const multipart = res.multipart
93
90
  ? {
91
+ key: res.multipart.key,
94
92
  uploadId: res.multipart.uploadId,
95
93
  parts: res.multipart.parts.map((part) => ({
96
94
  partNumber: part.partNumber,
@@ -103,12 +101,14 @@ export function EdgeStoreProvider(
103
101
  if (multipart) {
104
102
  return {
105
103
  accessUrl: res.accessUrl,
104
+ thumbnailUrl: res.thumbnailUrl,
106
105
  multipart,
107
106
  };
108
107
  } else if (res.signedUrl) {
109
108
  return {
110
109
  accessUrl: res.accessUrl,
111
110
  uploadUrl: res.signedUrl,
111
+ thumbnailUrl: res.thumbnailUrl,
112
112
  };
113
113
  } else {
114
114
  throw new Error('Could not get upload url');
@@ -123,6 +123,7 @@ export function EdgeStoreProvider(
123
123
  return {
124
124
  accessUrl: res.accessUrl,
125
125
  uploadUrl: res.signedUrl,
126
+ thumbnailUrl: res.thumbnailUrl,
126
127
  };
127
128
  }
128
129
  throw new Error('Could not get upload url');
@@ -142,6 +143,18 @@ export function EdgeStoreProvider(
142
143
  },
143
144
  };
144
145
  },
146
+ completeMultipartUpload: async ({ uploadId, key, parts }) => {
147
+ return await edgeStoreSdk.completeMultipartUpload({
148
+ uploadId,
149
+ key,
150
+ parts,
151
+ });
152
+ },
153
+ confirmUpload: async ({ url }) => {
154
+ return await edgeStoreSdk.confirmUpload({
155
+ url,
156
+ });
157
+ },
145
158
  deleteFile: async ({ url }) => {
146
159
  return await edgeStoreSdk.deleteFile({
147
160
  url,
@@ -1,2 +1 @@
1
- export * from './aws';
2
- export * from './edgestore';
1
+ export * from './types';
@@ -47,6 +47,7 @@ export type RequestUploadParams = {
47
47
  }[];
48
48
  metadata: AnyMetadata;
49
49
  replaceTargetUrl?: string;
50
+ temporary: boolean;
50
51
  };
51
52
  };
52
53
 
@@ -68,13 +69,28 @@ export type RequestUploadPartsRes = {
68
69
  };
69
70
  };
70
71
 
72
+ export type CompleteMultipartUploadParams = {
73
+ uploadId: string;
74
+ key: string;
75
+ parts: {
76
+ partNumber: number;
77
+ eTag: string;
78
+ }[];
79
+ };
80
+
81
+ export type CompleteMultipartUploadRes = {
82
+ success: boolean;
83
+ };
84
+
71
85
  export type RequestUploadRes =
72
86
  | {
73
87
  uploadUrl: string;
74
88
  accessUrl: string;
89
+ thumbnailUrl?: string | null;
75
90
  }
76
91
  | {
77
92
  multipart: {
93
+ key: string;
78
94
  uploadId: string;
79
95
  partSize: number;
80
96
  totalParts: number;
@@ -84,8 +100,18 @@ export type RequestUploadRes =
84
100
  }[];
85
101
  };
86
102
  accessUrl: string;
103
+ thumbnailUrl?: string | null;
87
104
  };
88
105
 
106
+ export type ConfirmUpload = {
107
+ bucket: AnyBuilder;
108
+ url: string;
109
+ };
110
+
111
+ export type ConfirmUploadRes = {
112
+ success: boolean;
113
+ };
114
+
89
115
  export type DeleteFileParams = {
90
116
  bucket: AnyBuilder;
91
117
  url: string;
@@ -105,5 +131,9 @@ export type Provider = {
105
131
  requestUploadParts: (
106
132
  params: RequestUploadPartsParams,
107
133
  ) => MaybePromise<RequestUploadPartsRes>;
134
+ completeMultipartUpload: (
135
+ params: CompleteMultipartUploadParams,
136
+ ) => MaybePromise<CompleteMultipartUploadRes>;
137
+ confirmUpload: (params: ConfirmUpload) => MaybePromise<ConfirmUploadRes>;
108
138
  deleteFile: (params: DeleteFileParams) => MaybePromise<DeleteFileRes>;
109
139
  };