@edgestore/server 0.0.0-alpha.12 → 0.0.0-alpha.14

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