@edgestore/server 0.1.0 → 0.1.2

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 (62) hide show
  1. package/README.md +6 -6
  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 +4 -4
  9. package/dist/adapters/next/app/index.d.ts.map +1 -1
  10. package/dist/adapters/next/app/index.js +22 -2
  11. package/dist/adapters/next/app/index.mjs +22 -2
  12. package/dist/adapters/next/pages/index.d.ts +4 -4
  13. package/dist/adapters/next/pages/index.d.ts.map +1 -1
  14. package/dist/adapters/next/pages/index.js +18 -2
  15. package/dist/adapters/next/pages/index.mjs +18 -2
  16. package/dist/adapters/shared.d.ts +35 -2
  17. package/dist/adapters/shared.d.ts.map +1 -1
  18. package/dist/core/client/index.d.ts +11 -3
  19. package/dist/core/client/index.d.ts.map +1 -1
  20. package/dist/core/index.d.ts +1 -1
  21. package/dist/core/index.d.ts.map +1 -1
  22. package/dist/core/index.js +5 -4
  23. package/dist/core/index.mjs +6 -5
  24. package/dist/core/internals/bucketBuilder.d.ts +2 -1
  25. package/dist/core/internals/bucketBuilder.d.ts.map +1 -1
  26. package/dist/core/sdk/index.d.ts +43 -2
  27. package/dist/core/sdk/index.d.ts.map +1 -1
  28. package/dist/{index-579b8015.mjs → index-30a3741e.mjs} +43 -2
  29. package/dist/{index-62d969e5.js → index-50ab9e08.js} +43 -2
  30. package/dist/{index-0a168903.js → index-f33a00fb.js} +41 -0
  31. package/dist/providers/aws/index.d.ts +28 -1
  32. package/dist/providers/aws/index.d.ts.map +1 -1
  33. package/dist/providers/aws/index.js +7 -1
  34. package/dist/providers/aws/index.mjs +7 -1
  35. package/dist/providers/edgestore/index.d.ts +13 -1
  36. package/dist/providers/edgestore/index.d.ts.map +1 -1
  37. package/dist/providers/edgestore/index.js +24 -10
  38. package/dist/providers/edgestore/index.mjs +24 -10
  39. package/dist/providers/index.d.ts +1 -2
  40. package/dist/providers/index.d.ts.map +1 -1
  41. package/dist/providers/index.js +2 -0
  42. package/dist/providers/index.mjs +1 -0
  43. package/dist/providers/types.d.ts +26 -2
  44. package/dist/providers/types.d.ts.map +1 -1
  45. package/dist/{shared-2a9c8307.mjs → shared-7fc08e14.mjs} +40 -2
  46. package/dist/{shared-ae739a04.js → shared-a5b84d0b.js} +41 -1
  47. package/dist/{shared-fac1b0a0.js → shared-a86ccc68.js} +39 -1
  48. package/package.json +13 -3
  49. package/providers/index.d.ts +1 -0
  50. package/providers/index.js +1 -0
  51. package/src/adapters/index.ts +6 -0
  52. package/src/adapters/next/app/index.ts +33 -7
  53. package/src/adapters/next/pages/index.ts +27 -7
  54. package/src/adapters/shared.ts +90 -2
  55. package/src/core/client/index.ts +15 -9
  56. package/src/core/index.ts +1 -1
  57. package/src/core/internals/bucketBuilder.ts +6 -1
  58. package/src/core/sdk/index.ts +83 -2
  59. package/src/providers/aws/index.ts +39 -5
  60. package/src/providers/edgestore/index.ts +34 -9
  61. package/src/providers/index.ts +1 -2
  62. package/src/providers/types.ts +34 -4
@@ -82,7 +82,8 @@ async function requestUpload(params) {
82
82
  type: fileInfo.type,
83
83
  fileName: fileInfo.fileName,
84
84
  extension: fileInfo.extension,
85
- replaceTargetUrl: fileInfo.replaceTargetUrl
85
+ replaceTargetUrl: fileInfo.replaceTargetUrl,
86
+ temporary: fileInfo.temporary
86
87
  }
87
88
  });
88
89
  if (!canUpload) {
@@ -176,6 +177,43 @@ async function requestUploadParts(params) {
176
177
  path
177
178
  });
178
179
  }
180
+ async function completeMultipartUpload(params) {
181
+ const { provider, router, ctxToken, body: { bucketName, uploadId, key, parts } } = params;
182
+ if (!ctxToken) {
183
+ throw new EdgeStoreError({
184
+ message: 'Missing edgestore-ctx cookie',
185
+ code: 'UNAUTHORIZED'
186
+ });
187
+ }
188
+ await getContext(ctxToken); // just to check if the token is valid
189
+ const bucket = router.buckets[bucketName];
190
+ if (!bucket) {
191
+ throw new Error(`Bucket ${bucketName} not found`);
192
+ }
193
+ return await provider.completeMultipartUpload({
194
+ uploadId,
195
+ key,
196
+ parts
197
+ });
198
+ }
199
+ async function confirmUpload(params) {
200
+ const { provider, router, ctxToken, body: { bucketName, url } } = params;
201
+ if (!ctxToken) {
202
+ throw new EdgeStoreError({
203
+ message: 'Missing edgestore-ctx cookie',
204
+ code: 'UNAUTHORIZED'
205
+ });
206
+ }
207
+ await getContext(ctxToken); // just to check if the token is valid
208
+ const bucket = router.buckets[bucketName];
209
+ if (!bucket) {
210
+ throw new Error(`Bucket ${bucketName} not found`);
211
+ }
212
+ await provider.confirmUpload({
213
+ bucket,
214
+ url
215
+ });
216
+ }
179
217
  async function deleteFile(params) {
180
218
  const { provider, router, ctxToken, body: { bucketName, url } } = params;
181
219
  if (!ctxToken) {
@@ -264,6 +302,8 @@ async function getContext(token) {
264
302
 
265
303
  exports.EDGE_STORE_ERROR_CODES = EDGE_STORE_ERROR_CODES;
266
304
  exports.EdgeStoreError = EdgeStoreError;
305
+ exports.completeMultipartUpload = completeMultipartUpload;
306
+ exports.confirmUpload = confirmUpload;
267
307
  exports.deleteFile = deleteFile;
268
308
  exports.init = init;
269
309
  exports.requestUpload = requestUpload;
@@ -78,6 +78,7 @@ async function requestUpload(params) {
78
78
  fileName: fileInfo.fileName,
79
79
  extension: fileInfo.extension,
80
80
  replaceTargetUrl: fileInfo.replaceTargetUrl,
81
+ temporary: fileInfo.temporary,
81
82
  },
82
83
  });
83
84
  if (!canUpload) {
@@ -166,6 +167,43 @@ async function requestUploadParts(params) {
166
167
  path,
167
168
  });
168
169
  }
170
+ async function completeMultipartUpload(params) {
171
+ const { provider, router, ctxToken, body: { bucketName, uploadId, key, parts }, } = params;
172
+ if (!ctxToken) {
173
+ throw new EdgeStoreError({
174
+ message: 'Missing edgestore-ctx cookie',
175
+ code: 'UNAUTHORIZED',
176
+ });
177
+ }
178
+ await getContext(ctxToken); // just to check if the token is valid
179
+ const bucket = router.buckets[bucketName];
180
+ if (!bucket) {
181
+ throw new Error(`Bucket ${bucketName} not found`);
182
+ }
183
+ return await provider.completeMultipartUpload({
184
+ uploadId,
185
+ key,
186
+ parts,
187
+ });
188
+ }
189
+ async function confirmUpload(params) {
190
+ const { provider, router, ctxToken, body: { bucketName, url }, } = params;
191
+ if (!ctxToken) {
192
+ throw new EdgeStoreError({
193
+ message: 'Missing edgestore-ctx cookie',
194
+ code: 'UNAUTHORIZED',
195
+ });
196
+ }
197
+ await getContext(ctxToken); // just to check if the token is valid
198
+ const bucket = router.buckets[bucketName];
199
+ if (!bucket) {
200
+ throw new Error(`Bucket ${bucketName} not found`);
201
+ }
202
+ await provider.confirmUpload({
203
+ bucket,
204
+ url,
205
+ });
206
+ }
169
207
  async function deleteFile(params) {
170
208
  const { provider, router, ctxToken, body: { bucketName, url }, } = params;
171
209
  if (!ctxToken) {
@@ -256,4 +294,4 @@ async function getContext(token) {
256
294
  return await decryptJWT(token);
257
295
  }
258
296
 
259
- export { EdgeStoreError as E, requestUploadParts as a, EDGE_STORE_ERROR_CODES as b, deleteFile as d, init as i, requestUpload as r };
297
+ export { EdgeStoreError as E, requestUploadParts as a, confirmUpload as b, completeMultipartUpload as c, deleteFile as d, EDGE_STORE_ERROR_CODES as e, init as i, requestUpload as r };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@edgestore/server",
3
- "version": "0.1.0",
4
- "description": "The best DX for uploading files from your Next.js app",
3
+ "version": "0.1.2",
4
+ "description": "Upload files with ease from React/Next.js",
5
5
  "homepage": "https://edgestore.dev",
6
6
  "repository": "https://github.com/edgestorejs/edgestore.git",
7
7
  "author": "Ravi <me@ravi.com>",
@@ -37,6 +37,11 @@
37
37
  "require": "./dist/core/index.js",
38
38
  "default": "./dist/core/index.js"
39
39
  },
40
+ "./adapters": {
41
+ "import": "./dist/adapters/index.mjs",
42
+ "require": "./dist/adapters/index.js",
43
+ "default": "./dist/adapters/index.js"
44
+ },
40
45
  "./adapters/next/pages": {
41
46
  "import": "./dist/adapters/next/pages/index.mjs",
42
47
  "require": "./dist/adapters/next/pages/index.js",
@@ -56,6 +61,11 @@
56
61
  "import": "./dist/providers/edgestore/index.mjs",
57
62
  "require": "./dist/providers/edgestore/index.js",
58
63
  "default": "./dist/providers/edgestore/index.js"
64
+ },
65
+ "./providers": {
66
+ "import": "./dist/providers/index.mjs",
67
+ "require": "./dist/providers/index.js",
68
+ "default": "./dist/providers/index.js"
59
69
  }
60
70
  },
61
71
  "files": [
@@ -94,5 +104,5 @@
94
104
  "typescript": "^5.1.6",
95
105
  "zod": "^3.21.4"
96
106
  },
97
- "gitHead": "02d8fe7865f94c75d0b09f6725f3ff3471abb549"
107
+ "gitHead": "99519b57aa7a5cbbe5cab16b85a70d437cb87435"
98
108
  }
@@ -0,0 +1 @@
1
+ export * from '../dist/providers';
@@ -0,0 +1 @@
1
+ module.exports = require('../dist/providers');
@@ -0,0 +1,6 @@
1
+ export type {
2
+ InitRes,
3
+ RequestUploadRes,
4
+ RequestUploadPartsRes,
5
+ DeleteFileRes,
6
+ } from './shared';
@@ -1,19 +1,23 @@
1
- import { NextRequest } from 'next/server';
2
- import { EdgeStoreRouter } from '../../../core/internals/bucketBuilder';
1
+ import { type NextRequest } from 'next/server';
2
+ import { type EdgeStoreRouter } from '../../../core/internals/bucketBuilder';
3
3
  import EdgeStoreError, {
4
4
  EDGE_STORE_ERROR_CODES,
5
5
  } from '../../../libs/errors/EdgeStoreError';
6
6
  import { EdgeStoreProvider } from '../../../providers/edgestore';
7
- import { Provider } from '../../../providers/types';
8
- import { MaybePromise } from '../../../types';
7
+ import { type Provider } from '../../../providers/types';
8
+ import { type MaybePromise } from '../../../types';
9
9
  import {
10
+ completeMultipartUpload,
11
+ confirmUpload,
10
12
  deleteFile,
11
- DeleteFileBody,
12
13
  init,
13
14
  requestUpload,
14
- RequestUploadBody,
15
15
  requestUploadParts,
16
- RequestUploadPartsParams,
16
+ type CompleteMultipartUploadBody,
17
+ type ConfirmUploadBody,
18
+ type DeleteFileBody,
19
+ type RequestUploadBody,
20
+ type RequestUploadPartsParams,
17
21
  } from '../../shared';
18
22
 
19
23
  export type CreateContextOptions = {
@@ -86,6 +90,28 @@ export function createEdgeStoreNextHandler<TCtx>(config: Config<TCtx>) {
86
90
  'Content-Type': 'application/json',
87
91
  },
88
92
  });
93
+ } else if (
94
+ req.nextUrl.pathname === '/api/edgestore/complete-multipart-upload'
95
+ ) {
96
+ await completeMultipartUpload({
97
+ provider,
98
+ router: config.router,
99
+ body: (await req.json()) as CompleteMultipartUploadBody,
100
+ ctxToken: req.cookies.get('edgestore-ctx')?.value,
101
+ });
102
+ return new Response(null, {
103
+ status: 200,
104
+ });
105
+ } else if (req.nextUrl.pathname === '/api/edgestore/confirm-upload') {
106
+ await confirmUpload({
107
+ provider,
108
+ router: config.router,
109
+ body: (await req.json()) as ConfirmUploadBody,
110
+ ctxToken: req.cookies.get('edgestore-ctx')?.value,
111
+ });
112
+ return new Response(null, {
113
+ status: 200,
114
+ });
89
115
  } else if (req.nextUrl.pathname === '/api/edgestore/delete-file') {
90
116
  await deleteFile({
91
117
  provider,
@@ -1,19 +1,23 @@
1
- import { NextApiRequest, NextApiResponse } from 'next/types';
2
- import { EdgeStoreRouter } from '../../../core/internals/bucketBuilder';
1
+ import { type NextApiRequest, type NextApiResponse } from 'next/types';
2
+ import { type EdgeStoreRouter } from '../../../core/internals/bucketBuilder';
3
3
  import EdgeStoreError, {
4
4
  EDGE_STORE_ERROR_CODES,
5
5
  } from '../../../libs/errors/EdgeStoreError';
6
6
  import { EdgeStoreProvider } from '../../../providers/edgestore';
7
- import { Provider } from '../../../providers/types';
8
- import { MaybePromise } from '../../../types';
7
+ import { type Provider } from '../../../providers/types';
8
+ import { type MaybePromise } from '../../../types';
9
9
  import {
10
+ completeMultipartUpload,
11
+ confirmUpload,
10
12
  deleteFile,
11
- DeleteFileBody,
12
13
  init,
13
14
  requestUpload,
14
- RequestUploadBody,
15
15
  requestUploadParts,
16
- RequestUploadPartsParams,
16
+ type CompleteMultipartUploadBody,
17
+ type ConfirmUploadBody,
18
+ type DeleteFileBody,
19
+ type RequestUploadBody,
20
+ type RequestUploadPartsParams,
17
21
  } from '../../shared';
18
22
 
19
23
  export type CreateContextOptions = {
@@ -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,
@@ -2,9 +2,12 @@ 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 { AnyBuilder, EdgeStoreRouter } from '../core/internals/bucketBuilder';
5
+ import {
6
+ type AnyBuilder,
7
+ type EdgeStoreRouter,
8
+ } from '../core/internals/bucketBuilder';
6
9
  import EdgeStoreError from '../libs/errors/EdgeStoreError';
7
- import { Provider } from '../providers/types';
10
+ import { type Provider } from '../providers/types';
8
11
  import { IMAGE_MIME_TYPES } from './imageTypes';
9
12
 
10
13
  // TODO: change it to 1 hour when we have a way to refresh the token
@@ -53,6 +56,7 @@ export type RequestUploadBody = {
53
56
  extension: string;
54
57
  fileName?: string;
55
58
  replaceTargetUrl?: string;
59
+ temporary: boolean;
56
60
  };
57
61
  };
58
62
 
@@ -90,6 +94,7 @@ export async function requestUpload<TCtx>(params: {
90
94
  fileName: fileInfo.fileName,
91
95
  extension: fileInfo.extension,
92
96
  replaceTargetUrl: fileInfo.replaceTargetUrl,
97
+ temporary: fileInfo.temporary,
93
98
  },
94
99
  });
95
100
  if (!canUpload) {
@@ -203,6 +208,82 @@ export async function requestUploadParts<TCtx>(params: {
203
208
  });
204
209
  }
205
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
+
206
287
  export type DeleteFileBody = {
207
288
  bucketName: string;
208
289
  url: string;
@@ -336,3 +417,10 @@ async function getContext(token?: string) {
336
417
  }
337
418
  return await decryptJWT(token);
338
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>>;
@@ -1,10 +1,10 @@
1
- import { AnyRouter, Comparison } from '..';
2
- import { Simplify } from '../../types';
1
+ import { type AnyRouter, type Comparison } from '..';
2
+ import { type Simplify } from '../../types';
3
3
  import {
4
- AnyBuilder,
5
- InferBucketPathKeys,
6
- InferBucketPathObject,
7
- InferMetadataObject,
4
+ type AnyBuilder,
5
+ type InferBucketPathKeys,
6
+ type InferBucketPathObject,
7
+ type InferMetadataObject,
8
8
  } from '../internals/bucketBuilder';
9
9
  import { initEdgeStoreSdk } from '../sdk';
10
10
 
@@ -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) {
package/src/core/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { EdgeStoreRouter } from './internals/bucketBuilder';
1
+ import { type EdgeStoreRouter } from './internals/bucketBuilder';
2
2
 
3
3
  export * from './client';
4
4
  export * from './sdk';
@@ -1,5 +1,9 @@
1
1
  import { z } from 'zod';
2
- import { KeysOfUnion, MaybePromise, Simplify } from '../../types';
2
+ import {
3
+ type KeysOfUnion,
4
+ type MaybePromise,
5
+ type Simplify,
6
+ } from '../../types';
3
7
  import { createPathParamProxy } from './createPathParamProxy';
4
8
 
5
9
  type Merge<TType, TWith> = {
@@ -113,6 +117,7 @@ type FileInfo = {
113
117
  extension: string;
114
118
  fileName?: string;
115
119
  replaceTargetUrl?: string;
120
+ temporary: boolean;
116
121
  };
117
122
 
118
123
  type BeforeUploadFn<TCtx, TDef extends AnyDef> = (params: {
@@ -1,6 +1,6 @@
1
- import { AnyRouter } from '..';
1
+ import { type AnyRouter } from '..';
2
2
  import EdgeStoreCredentialsError from '../../libs/errors/EdgeStoreCredentialsError';
3
- import { AnyContext, AnyMetadata } from '../internals/bucketBuilder';
3
+ import { type AnyContext, type AnyMetadata } from '../internals/bucketBuilder';
4
4
 
5
5
  const API_ENDPOINT =
6
6
  process.env.EDGE_STORE_API_ENDPOINT ?? 'https://api.edgestore.dev';
@@ -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,
@@ -6,13 +6,40 @@ import {
6
6
  } from '@aws-sdk/client-s3';
7
7
  import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
8
8
  import { v4 as uuidv4 } from 'uuid';
9
- import { Provider } from '../types';
9
+ import { type Provider } from '../types';
10
10
 
11
11
  export type AWSProviderOptions = {
12
+ /**
13
+ * Access key for AWS credentials.
14
+ * Can also be set via the `ES_AWS_ACCESS_KEY_ID` environment variable.
15
+ *
16
+ * If unset, the SDK will attempt to use the default credentials provider chain.
17
+ */
12
18
  accessKeyId?: string;
19
+ /**
20
+ * Secret access key for AWS credentials.
21
+ * Can also be set via the `ES_AWS_SECRET_ACCESS_KEY` environment variable.
22
+ *
23
+ * If unset, the SDK will attempt to use the default credentials provider chain.
24
+ */
13
25
  secretAccessKey?: string;
26
+ /**
27
+ * AWS region to use.
28
+ * Can also be set via the `ES_AWS_REGION` environment variable.
29
+ */
14
30
  region?: string;
31
+ /**
32
+ * Name of the S3 bucket to use.
33
+ * Can also be set via the `ES_AWS_BUCKET_NAME` environment variable.
34
+ */
15
35
  bucketName?: string;
36
+ /**
37
+ * Base URL to use for accessing files.
38
+ * Only needed if you are using a custom domain or cloudfront.
39
+ *
40
+ * Can also be set via the `EDGE_STORE_BASE_URL` environment variable.
41
+ */
42
+ baseUrl?: string;
16
43
  };
17
44
 
18
45
  export function AWSProvider(options?: AWSProviderOptions): Provider {
@@ -23,6 +50,11 @@ export function AWSProvider(options?: AWSProviderOptions): Provider {
23
50
  bucketName = process.env.ES_AWS_BUCKET_NAME,
24
51
  } = options ?? {};
25
52
 
53
+ const baseUrl =
54
+ options?.baseUrl ??
55
+ process.env.EDGE_STORE_BASE_URL ??
56
+ `https://${bucketName}.s3.${region}.amazonaws.com`;
57
+
26
58
  const credentials =
27
59
  accessKeyId && secretAccessKey
28
60
  ? {
@@ -32,10 +64,6 @@ export function AWSProvider(options?: AWSProviderOptions): Provider {
32
64
  : undefined;
33
65
  const s3Client = new S3Client({ region, credentials });
34
66
 
35
- const baseUrl =
36
- process.env.EDGE_STORE_BASE_URL ??
37
- `https://${bucketName}.s3.${region}.amazonaws.com`;
38
-
39
67
  return {
40
68
  async init() {
41
69
  return {};
@@ -93,6 +121,12 @@ export function AWSProvider(options?: AWSProviderOptions): Provider {
93
121
  async requestUploadParts() {
94
122
  throw new Error('Not implemented');
95
123
  },
124
+ async completeMultipartUpload() {
125
+ throw new Error('Not implemented');
126
+ },
127
+ async confirmUpload() {
128
+ throw new Error('Not implemented');
129
+ },
96
130
  async deleteFile({ url }) {
97
131
  const path = url.replace(`${baseUrl}/`, '');
98
132
  await s3Client.send(