@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
@@ -10,10 +10,6 @@ type Merge<TType, TWith> = {
10
10
  : TWith[TKey & keyof TWith];
11
11
  };
12
12
 
13
- type OverwriteIfDefined<TType, TWith> = UnsetMarker extends TType
14
- ? TWith
15
- : Simplify<TType & TWith>;
16
-
17
13
  type ConvertStringToFunction<TType> = {
18
14
  [K in keyof TType]: TType[K] extends object
19
15
  ? Simplify<ConvertStringToFunction<TType[K]>>
@@ -33,23 +29,33 @@ type InferBucketPathKeysFromDef<TDef extends AnyDef> = KeysOfUnion<
33
29
  TDef['path'][number]
34
30
  >;
35
31
 
32
+ export type InferBucketPathObject<TBucket extends Builder<any, AnyDef>> =
33
+ InferBucketPathKeys<TBucket> extends never
34
+ ? Record<string, never>
35
+ : {
36
+ [TKey in InferBucketPathKeys<TBucket>]: string;
37
+ };
38
+
39
+ export type InferBucketPathObjectFromDef<TDef extends AnyDef> =
40
+ InferBucketPathKeysFromDef<TDef> extends never
41
+ ? Record<string, never>
42
+ : {
43
+ [TKey in InferBucketPathKeysFromDef<TDef>]: string;
44
+ };
45
+
36
46
  export type InferMetadataObject<TBucket extends Builder<any, AnyDef>> =
37
47
  TBucket['_def']['metadata'] extends (...args: any) => any
38
48
  ? Awaited<ReturnType<TBucket['_def']['metadata']>>
39
- : TBucket['_def']['metadata'] extends ((...args: any) => any) | undefined
40
- ? any
41
- : never;
49
+ : Record<string, never>;
42
50
 
43
51
  type InferMetadataObjectFromDef<TDef extends AnyDef> =
44
52
  TDef['metadata'] extends (...args: any) => any
45
53
  ? Awaited<ReturnType<TDef['metadata']>>
46
- : TDef['metadata'] extends ((...args: any) => any) | undefined
47
- ? any
48
- : never;
54
+ : Record<string, never>;
49
55
 
50
56
  export type AnyContext = Record<string, string | undefined | null>;
51
57
 
52
- export type AnyInput = z.AnyZodObject;
58
+ export type AnyInput = z.AnyZodObject | z.ZodNever;
53
59
 
54
60
  export type AnyPath = Record<string, () => string>[];
55
61
 
@@ -57,10 +63,6 @@ type PathParam<TPath extends AnyPath> = {
57
63
  path: keyof UnionToIntersection<TPath[number]>;
58
64
  };
59
65
 
60
- const unsetMarker = Symbol('unsetMarker');
61
-
62
- type UnsetMarker = typeof unsetMarker;
63
-
64
66
  type Conditions<TPath extends AnyPath> = {
65
67
  eq?: string | PathParam<TPath>;
66
68
  lt?: string | PathParam<TPath>;
@@ -86,10 +88,30 @@ export type AccessControlSchema<TCtx, TDef extends AnyDef> = Merge<
86
88
  }
87
89
  >;
88
90
 
91
+ type BucketConfig = {
92
+ /**
93
+ * Maximum size for a single file in bytes
94
+ *
95
+ * e.g. 1024 * 1024 * 10 = 10MB
96
+ */
97
+ maxSize?: number;
98
+ /**
99
+ * Accepted MIME types
100
+ *
101
+ * e.g. ['image/jpeg', 'image/png']
102
+ *
103
+ * You can also use wildcards after the slash:
104
+ *
105
+ * e.g. ['image/*']
106
+ */
107
+ accept?: string[];
108
+ };
109
+
89
110
  type FileInfo = {
90
111
  size: number;
91
112
  type: string;
92
113
  extension: string;
114
+ fileName?: string;
93
115
  replaceTargetUrl?: string;
94
116
  };
95
117
 
@@ -101,41 +123,43 @@ type BeforeUploadFn<TCtx, TDef extends AnyDef> = (params: {
101
123
 
102
124
  type BeforeDeleteFn<TCtx, TDef extends AnyDef> = (params: {
103
125
  ctx: TCtx;
104
- file: {
126
+ fileInfo: {
105
127
  url: string;
106
128
  size: number;
107
129
  uploadedAt: Date;
108
- path: {
109
- [TKey in InferBucketPathKeysFromDef<TDef>]: string;
110
- };
130
+ path: InferBucketPathObjectFromDef<TDef>;
111
131
  metadata: InferMetadataObjectFromDef<TDef>;
112
132
  };
113
133
  }) => MaybePromise<boolean>;
114
134
 
115
- type AnyMetadata = Record<string, string | undefined | null>;
135
+ export type AnyMetadata = Record<string, string | undefined | null>;
116
136
 
117
137
  type MetadataFn<
118
138
  TCtx,
119
- TDef extends AnyDef,
139
+ TInput extends AnyInput,
120
140
  TMetadata extends AnyMetadata,
121
- > = (params: {
122
- ctx: TCtx;
123
- input: z.infer<TDef['input']>;
124
- }) => MaybePromise<TMetadata>;
141
+ > = (params: { ctx: TCtx; input: z.infer<TInput> }) => MaybePromise<TMetadata>;
142
+
143
+ export type AnyMetadataFn = MetadataFn<any, AnyInput, AnyMetadata>;
125
144
 
126
145
  type BucketType = 'IMAGE' | 'FILE';
127
146
 
128
- type Def<TInput extends AnyInput, TPath extends AnyPath> = {
129
- type: any;
147
+ type Def<
148
+ TInput extends AnyInput,
149
+ TPath extends AnyPath,
150
+ TMetadata extends AnyMetadataFn,
151
+ > = {
152
+ type: BucketType;
130
153
  input: TInput;
131
154
  path: TPath;
132
- metadata?: MetadataFn<any, any, any>;
155
+ metadata: TMetadata;
156
+ bucketConfig?: BucketConfig;
133
157
  accessControl?: AccessControlSchema<any, any>;
134
158
  beforeUpload?: BeforeUploadFn<any, any>;
135
159
  beforeDelete?: BeforeDeleteFn<any, any>;
136
160
  };
137
161
 
138
- type AnyDef = Def<any, any>;
162
+ type AnyDef = Def<AnyInput, AnyPath, AnyMetadataFn>;
139
163
 
140
164
  type Builder<TCtx, TDef extends AnyDef> = {
141
165
  /** only used for types */
@@ -146,20 +170,38 @@ type Builder<TCtx, TDef extends AnyDef> = {
146
170
  * @internal
147
171
  */
148
172
  _def: TDef;
173
+ /**
174
+ * You can set an input that will be required in every upload from the client.
175
+ *
176
+ * This can be used to add additional information to the file, like choose the file path or add metadata.
177
+ */
149
178
  input<TInput extends AnyInput>(
150
179
  input: TInput,
151
180
  ): Builder<
152
181
  TCtx,
153
182
  {
154
183
  type: TDef['type'];
155
- input: OverwriteIfDefined<TDef['input'], TInput>;
184
+ input: TInput;
156
185
  path: TDef['path'];
157
186
  metadata: TDef['metadata'];
187
+ bucketConfig: TDef['bucketConfig'];
158
188
  accessControl: TDef['accessControl'];
159
189
  beforeUpload: TDef['beforeUpload'];
160
190
  beforeDelete: TDef['beforeDelete'];
161
191
  }
162
192
  >;
193
+ /**
194
+ * The `path` is similar to folders in a file system.
195
+ * But in this case, every segment of the path must have a meaning.
196
+ *
197
+ * ```
198
+ * // e.g. 123/profile/file.jpg
199
+ * {
200
+ * author: '123',
201
+ * type: 'profile',
202
+ * }
203
+ * ```
204
+ */
163
205
  path<TParams extends AnyPath>(
164
206
  pathResolver: (params: {
165
207
  ctx: Simplify<ConvertStringToFunction<TCtx>>;
@@ -172,13 +214,19 @@ type Builder<TCtx, TDef extends AnyDef> = {
172
214
  input: TDef['input'];
173
215
  path: TParams;
174
216
  metadata: TDef['metadata'];
217
+ bucketConfig: TDef['bucketConfig'];
175
218
  accessControl: TDef['accessControl'];
176
219
  beforeUpload: TDef['beforeUpload'];
177
220
  beforeDelete: TDef['beforeDelete'];
178
221
  }
179
222
  >;
223
+ /**
224
+ * This metadata will be added to every file uploaded to this bucket.
225
+ *
226
+ * This can be used, for example, to filter files.
227
+ */
180
228
  metadata<TMetadata extends AnyMetadata>(
181
- metadata: MetadataFn<TCtx, TDef, TMetadata>,
229
+ metadata: MetadataFn<TCtx, TDef['input'], TMetadata>,
182
230
  ): Builder<
183
231
  TCtx,
184
232
  {
@@ -186,11 +234,18 @@ type Builder<TCtx, TDef extends AnyDef> = {
186
234
  input: TDef['input'];
187
235
  path: TDef['path'];
188
236
  metadata: MetadataFn<any, any, TMetadata>;
237
+ bucketConfig: TDef['bucketConfig'];
189
238
  accessControl: TDef['accessControl'];
190
239
  beforeUpload: TDef['beforeUpload'];
191
240
  beforeDelete: TDef['beforeDelete'];
192
241
  }
193
242
  >;
243
+ /**
244
+ * If you set this, your bucket will automatically be configured as a protected bucket.
245
+ *
246
+ * This means that images will only be accessible from within your app.
247
+ * And only if it passes the check set in this function.
248
+ */
194
249
  accessControl(accessControl: AccessControlSchema<TCtx, TDef>): Builder<
195
250
  TCtx,
196
251
  {
@@ -198,11 +253,17 @@ type Builder<TCtx, TDef extends AnyDef> = {
198
253
  input: TDef['input'];
199
254
  path: TDef['path'];
200
255
  metadata: TDef['metadata'];
256
+ bucketConfig: TDef['bucketConfig'];
201
257
  accessControl: AccessControlSchema<any, any>;
202
258
  beforeUpload: TDef['beforeUpload'];
203
259
  beforeDelete: TDef['beforeDelete'];
204
260
  }
205
261
  >;
262
+ /**
263
+ * return `true` to allow upload
264
+ *
265
+ * By default every upload from your app is allowed.
266
+ */
206
267
  beforeUpload(beforeUpload: BeforeUploadFn<TCtx, TDef>): Builder<
207
268
  TCtx,
208
269
  {
@@ -210,11 +271,17 @@ type Builder<TCtx, TDef extends AnyDef> = {
210
271
  input: TDef['input'];
211
272
  path: TDef['path'];
212
273
  metadata: TDef['metadata'];
274
+ bucketConfig: TDef['bucketConfig'];
213
275
  accessControl: TDef['accessControl'];
214
276
  beforeUpload: BeforeUploadFn<any, any>;
215
277
  beforeDelete: TDef['beforeDelete'];
216
278
  }
217
279
  >;
280
+ /**
281
+ * return `true` to allow delete
282
+ *
283
+ * This function must be defined if you want to delete files directly from the client.
284
+ */
218
285
  beforeDelete(beforeDelete: BeforeDeleteFn<TCtx, TDef>): Builder<
219
286
  TCtx,
220
287
  {
@@ -222,6 +289,7 @@ type Builder<TCtx, TDef extends AnyDef> = {
222
289
  input: TDef['input'];
223
290
  path: TDef['path'];
224
291
  metadata: TDef['metadata'];
292
+ bucketConfig: TDef['bucketConfig'];
225
293
  accessControl: TDef['accessControl'];
226
294
  beforeUpload: TDef['beforeUpload'];
227
295
  beforeDelete: BeforeDeleteFn<any, any>;
@@ -244,16 +312,23 @@ const createNewBuilder = (initDef: AnyDef, newDef: Partial<AnyDef>) => {
244
312
  );
245
313
  };
246
314
 
247
- function createBuilder<TCtx, TType extends BucketType>(
315
+ function createBuilder<
316
+ TCtx,
317
+ TType extends BucketType,
318
+ TInput extends AnyInput = z.ZodNever,
319
+ TPath extends AnyPath = [],
320
+ TMetadata extends AnyMetadataFn = () => Record<string, never>,
321
+ >(
248
322
  opts: { type: TType },
249
323
  initDef?: Partial<AnyDef>,
250
324
  ): Builder<
251
325
  TCtx,
252
326
  {
253
327
  type: TType;
254
- input: UnsetMarker;
255
- path: UnsetMarker;
256
- metadata?: MetadataFn<any, any, any>;
328
+ input: TInput;
329
+ path: TPath;
330
+ metadata: TMetadata;
331
+ bucketConfig?: BucketConfig;
257
332
  accessControl?: AccessControlSchema<any, any>;
258
333
  beforeUpload?: BeforeUploadFn<any, any>;
259
334
  beforeDelete?: BeforeDeleteFn<any, any>;
@@ -263,6 +338,7 @@ function createBuilder<TCtx, TType extends BucketType>(
263
338
  type: opts.type,
264
339
  input: z.never(),
265
340
  path: [],
341
+ metadata: () => ({}),
266
342
  ...initDef,
267
343
  };
268
344
 
@@ -270,6 +346,7 @@ function createBuilder<TCtx, TType extends BucketType>(
270
346
  $config: {
271
347
  ctx: undefined as TCtx,
272
348
  },
349
+ // @ts-expect-error - I think it would be too much work to make this type correct.
273
350
  _def,
274
351
  input(input) {
275
352
  return createNewBuilder(_def, {
@@ -309,7 +386,7 @@ function createBuilder<TCtx, TType extends BucketType>(
309
386
  };
310
387
  }
311
388
 
312
- class EdgeStoreBuilder<TCtx = object> {
389
+ class EdgeStoreBuilder<TCtx = Record<string, never>> {
313
390
  context<TNewContext extends AnyContext>() {
314
391
  return new EdgeStoreBuilder<TNewContext>();
315
392
  }
@@ -343,17 +420,28 @@ function createRouterFactory<TCtx>() {
343
420
  };
344
421
  }
345
422
 
423
+ function initBucket<TCtx, TType extends BucketType>(
424
+ type: TType,
425
+ config?: BucketConfig,
426
+ ) {
427
+ return createBuilder<TCtx, TType>({ type }, { bucketConfig: config });
428
+ }
429
+
346
430
  function createEdgeStoreInner<TCtx>() {
347
431
  return function initEdgeStoreInner() {
348
432
  return {
349
433
  /**
350
434
  * Builder object for creating an image bucket
351
435
  */
352
- imageBucket: createBuilder<TCtx, 'IMAGE'>({ type: 'IMAGE' }),
436
+ imageBucket(config?: BucketConfig) {
437
+ return initBucket<TCtx, 'IMAGE'>('IMAGE', config);
438
+ },
353
439
  /**
354
440
  * Builder object for creating a file bucket
355
441
  */
356
- fileBucket: createBuilder<TCtx, 'FILE'>({ type: 'FILE' }),
442
+ fileBucket(config?: BucketConfig) {
443
+ return initBucket<TCtx, 'FILE'>('FILE', config);
444
+ },
357
445
  /**
358
446
  * Create a router
359
447
  */
@@ -376,7 +464,7 @@ export const initEdgeStore = new EdgeStoreBuilder();
376
464
 
377
465
  // const es = initEdgeStore.context<Context>().create();
378
466
 
379
- // const imagesBucket = es.imageBucket
467
+ // const imagesBucket = es.imageBucket()
380
468
  // .input(
381
469
  // z.object({
382
470
  // type: z.enum(['profile', 'post']),
@@ -391,7 +479,7 @@ export const initEdgeStore = new EdgeStoreBuilder();
391
479
  // .beforeUpload(() => {
392
480
  // return true;
393
481
  // });
394
- // const a = es.imageBucket
482
+ // const a = es.imageBucket()
395
483
  // .input(z.object({ type: z.string(), someMeta: z.string().optional() }))
396
484
  // .path(({ ctx, input }) => [{ author: ctx.userId }, { type: input.type }])
397
485
  // .metadata(({ ctx, input }) => ({
@@ -415,7 +503,7 @@ export const initEdgeStore = new EdgeStoreBuilder();
415
503
  // return true;
416
504
  // });
417
505
 
418
- // const b = es.imageBucket.path(({ ctx }) => [{ author: ctx.userId }]);
506
+ // const b = es.imageBucket().path(({ ctx }) => [{ author: ctx.userId }]);
419
507
 
420
508
  // const router = es.router({
421
509
  // original: imagesBucket,
@@ -1,21 +1,21 @@
1
1
  import { AnyRouter } from '..';
2
2
  import EdgeStoreCredentialsError from '../../libs/errors/EdgeStoreCredentialsError';
3
- import { AnyContext } from '../internals/bucketBuilder';
3
+ import { AnyContext, AnyMetadata } from '../internals/bucketBuilder';
4
4
 
5
5
  const API_ENDPOINT =
6
- process.env.EDGE_STORE_API_ENDPOINT ?? 'https://api.edge-store.com';
6
+ process.env.EDGE_STORE_API_ENDPOINT ?? 'https://api.edgestore.dev';
7
7
 
8
8
  type FileInfoForUpload = {
9
9
  size: number;
10
10
  extension: string;
11
+ type?: string;
11
12
  isPublic: boolean;
12
13
  path: {
13
14
  key: string;
14
15
  value: string;
15
16
  }[];
16
- metadata?: {
17
- [key: string]: string;
18
- };
17
+ metadata: AnyMetadata;
18
+ fileName?: string;
19
19
  replaceTargetUrl?: string;
20
20
  };
21
21
 
@@ -74,7 +74,7 @@ async function makeRequest<TOutput>(params: {
74
74
  },
75
75
  });
76
76
  if (!res.ok) {
77
- throw new Error(`Failed to make request to ${path}`);
77
+ throw new Error(`Failed to make request to ${path}: ${await res.text()}`);
78
78
  }
79
79
  return (await res.json()) as TOutput;
80
80
  }
@@ -182,7 +182,9 @@ export const edgeStoreRawSdk = {
182
182
  path: fileInfo.path,
183
183
  extension: fileInfo.extension,
184
184
  size: fileInfo.size,
185
+ mimeType: fileInfo.type,
185
186
  metadata: fileInfo.metadata,
187
+ fileName: fileInfo.fileName,
186
188
  replaceTargetUrl: fileInfo.replaceTargetUrl,
187
189
  },
188
190
  });
@@ -2,13 +2,11 @@ import { initEdgeStoreSdk } from '../../core/sdk';
2
2
  import EdgeStoreCredentialsError from '../../libs/errors/EdgeStoreCredentialsError';
3
3
  import { Provider, RequestUploadRes } from '../types';
4
4
 
5
- const DEFAULT_BASE_URL =
6
- process.env.EDGE_STORE_BASE_URL ?? 'https://files.edge-store.com';
5
+ const DEFAULT_BASE_URL = 'https://files.edgestore.dev';
7
6
 
8
7
  export type EdgeStoreProviderOptions = {
9
8
  accessKey?: string;
10
9
  secretKey?: string;
11
- baseUrl?: string;
12
10
  };
13
11
 
14
12
  export function EdgeStoreProvider(
@@ -17,9 +15,10 @@ export function EdgeStoreProvider(
17
15
  const {
18
16
  accessKey = process.env.EDGE_STORE_ACCESS_KEY,
19
17
  secretKey = process.env.EDGE_STORE_SECRET_KEY,
20
- baseUrl = process.env.EDGE_STORE_BASE_URL ?? DEFAULT_BASE_URL,
21
18
  } = options ?? {};
22
19
 
20
+ const baseUrl = process.env.EDGE_STORE_BASE_URL ?? DEFAULT_BASE_URL;
21
+
23
22
  if (!accessKey || !secretKey) {
24
23
  throw new EdgeStoreCredentialsError();
25
24
  }
@@ -1,4 +1,8 @@
1
- import { AnyBuilder, EdgeStoreRouter } from '../core/internals/bucketBuilder';
1
+ import {
2
+ AnyBuilder,
3
+ AnyMetadata,
4
+ EdgeStoreRouter,
5
+ } from '../core/internals/bucketBuilder';
2
6
  import { MaybePromise } from '../types';
3
7
 
4
8
  export type InitParams = {
@@ -41,9 +45,7 @@ export type RequestUploadParams = {
41
45
  key: string;
42
46
  value: string;
43
47
  }[];
44
- metadata?: {
45
- [key: string]: string;
46
- };
48
+ metadata: AnyMetadata;
47
49
  replaceTargetUrl?: string;
48
50
  };
49
51
  };