@edgestore/shared 0.6.0-canary.2 → 0.6.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.
- package/dist/errors/EdgeStoreError.js +52 -0
- package/dist/errors/EdgeStoreError.mjs +49 -0
- package/dist/errors/index.js +25 -0
- package/dist/errors/index.mjs +23 -0
- package/dist/index.js +7 -290
- package/dist/index.mjs +3 -288
- package/dist/internals/bucketBuilder.js +193 -0
- package/dist/internals/bucketBuilder.mjs +191 -0
- package/dist/internals/createPathParamProxy.js +31 -0
- package/dist/internals/createPathParamProxy.mjs +29 -0
- package/package.json +14 -9
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function _define_property(obj, key, value) {
|
|
4
|
+
if (key in obj) {
|
|
5
|
+
Object.defineProperty(obj, key, {
|
|
6
|
+
value: value,
|
|
7
|
+
enumerable: true,
|
|
8
|
+
configurable: true,
|
|
9
|
+
writable: true
|
|
10
|
+
});
|
|
11
|
+
} else {
|
|
12
|
+
obj[key] = value;
|
|
13
|
+
}
|
|
14
|
+
return obj;
|
|
15
|
+
}
|
|
16
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */ const EDGE_STORE_ERROR_CODES = {
|
|
17
|
+
BAD_REQUEST: 400,
|
|
18
|
+
FILE_TOO_LARGE: 400,
|
|
19
|
+
MIME_TYPE_NOT_ALLOWED: 400,
|
|
20
|
+
UNAUTHORIZED: 401,
|
|
21
|
+
UPLOAD_NOT_ALLOWED: 403,
|
|
22
|
+
DELETE_NOT_ALLOWED: 403,
|
|
23
|
+
CREATE_CONTEXT_ERROR: 500,
|
|
24
|
+
SERVER_ERROR: 500
|
|
25
|
+
};
|
|
26
|
+
class EdgeStoreError extends Error {
|
|
27
|
+
formattedMessage() {
|
|
28
|
+
return `${this.message}${this.details ? `\n Details: ${JSON.stringify(this.details)}` : ''}${this.cause ? `\n Caused by: ${this.cause.message}` : ''}`;
|
|
29
|
+
}
|
|
30
|
+
formattedJson() {
|
|
31
|
+
return {
|
|
32
|
+
message: this.code === 'SERVER_ERROR' ? 'Internal server error' : this.message,
|
|
33
|
+
code: this.code,
|
|
34
|
+
details: this.details
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
constructor(opts){
|
|
38
|
+
super(opts.message);
|
|
39
|
+
_define_property(this, "cause", void 0);
|
|
40
|
+
_define_property(this, "code", void 0);
|
|
41
|
+
_define_property(this, "level", void 0);
|
|
42
|
+
_define_property(this, "details", void 0);
|
|
43
|
+
this.name = 'EdgeStoreError';
|
|
44
|
+
this.code = opts.code;
|
|
45
|
+
this.cause = opts.cause;
|
|
46
|
+
this.level = EDGE_STORE_ERROR_CODES[opts.code] >= 500 ? 'error' : 'warn';
|
|
47
|
+
this.details = 'details' in opts ? opts.details : undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
exports.EDGE_STORE_ERROR_CODES = EDGE_STORE_ERROR_CODES;
|
|
52
|
+
exports.EdgeStoreError = EdgeStoreError;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
function _define_property(obj, key, value) {
|
|
2
|
+
if (key in obj) {
|
|
3
|
+
Object.defineProperty(obj, key, {
|
|
4
|
+
value: value,
|
|
5
|
+
enumerable: true,
|
|
6
|
+
configurable: true,
|
|
7
|
+
writable: true
|
|
8
|
+
});
|
|
9
|
+
} else {
|
|
10
|
+
obj[key] = value;
|
|
11
|
+
}
|
|
12
|
+
return obj;
|
|
13
|
+
}
|
|
14
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */ const EDGE_STORE_ERROR_CODES = {
|
|
15
|
+
BAD_REQUEST: 400,
|
|
16
|
+
FILE_TOO_LARGE: 400,
|
|
17
|
+
MIME_TYPE_NOT_ALLOWED: 400,
|
|
18
|
+
UNAUTHORIZED: 401,
|
|
19
|
+
UPLOAD_NOT_ALLOWED: 403,
|
|
20
|
+
DELETE_NOT_ALLOWED: 403,
|
|
21
|
+
CREATE_CONTEXT_ERROR: 500,
|
|
22
|
+
SERVER_ERROR: 500
|
|
23
|
+
};
|
|
24
|
+
class EdgeStoreError extends Error {
|
|
25
|
+
formattedMessage() {
|
|
26
|
+
return `${this.message}${this.details ? `\n Details: ${JSON.stringify(this.details)}` : ''}${this.cause ? `\n Caused by: ${this.cause.message}` : ''}`;
|
|
27
|
+
}
|
|
28
|
+
formattedJson() {
|
|
29
|
+
return {
|
|
30
|
+
message: this.code === 'SERVER_ERROR' ? 'Internal server error' : this.message,
|
|
31
|
+
code: this.code,
|
|
32
|
+
details: this.details
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
constructor(opts){
|
|
36
|
+
super(opts.message);
|
|
37
|
+
_define_property(this, "cause", void 0);
|
|
38
|
+
_define_property(this, "code", void 0);
|
|
39
|
+
_define_property(this, "level", void 0);
|
|
40
|
+
_define_property(this, "details", void 0);
|
|
41
|
+
this.name = 'EdgeStoreError';
|
|
42
|
+
this.code = opts.code;
|
|
43
|
+
this.cause = opts.cause;
|
|
44
|
+
this.level = EDGE_STORE_ERROR_CODES[opts.code] >= 500 ? 'error' : 'warn';
|
|
45
|
+
this.details = 'details' in opts ? opts.details : undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { EDGE_STORE_ERROR_CODES, EdgeStoreError };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function _define_property(obj, key, value) {
|
|
4
|
+
if (key in obj) {
|
|
5
|
+
Object.defineProperty(obj, key, {
|
|
6
|
+
value: value,
|
|
7
|
+
enumerable: true,
|
|
8
|
+
configurable: true,
|
|
9
|
+
writable: true
|
|
10
|
+
});
|
|
11
|
+
} else {
|
|
12
|
+
obj[key] = value;
|
|
13
|
+
}
|
|
14
|
+
return obj;
|
|
15
|
+
}
|
|
16
|
+
class EdgeStoreApiClientError extends Error {
|
|
17
|
+
constructor(opts){
|
|
18
|
+
super(opts.response.message);
|
|
19
|
+
_define_property(this, "data", void 0);
|
|
20
|
+
this.name = 'EdgeStoreApiClientError';
|
|
21
|
+
this.data = opts.response;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
exports.EdgeStoreApiClientError = EdgeStoreApiClientError;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
function _define_property(obj, key, value) {
|
|
2
|
+
if (key in obj) {
|
|
3
|
+
Object.defineProperty(obj, key, {
|
|
4
|
+
value: value,
|
|
5
|
+
enumerable: true,
|
|
6
|
+
configurable: true,
|
|
7
|
+
writable: true
|
|
8
|
+
});
|
|
9
|
+
} else {
|
|
10
|
+
obj[key] = value;
|
|
11
|
+
}
|
|
12
|
+
return obj;
|
|
13
|
+
}
|
|
14
|
+
class EdgeStoreApiClientError extends Error {
|
|
15
|
+
constructor(opts){
|
|
16
|
+
super(opts.response.message);
|
|
17
|
+
_define_property(this, "data", void 0);
|
|
18
|
+
this.name = 'EdgeStoreApiClientError';
|
|
19
|
+
this.data = opts.response;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { EdgeStoreApiClientError };
|
package/dist/index.js
CHANGED
|
@@ -1,295 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
var index = require('./errors/index.js');
|
|
4
|
+
var bucketBuilder = require('./internals/bucketBuilder.js');
|
|
5
|
+
var EdgeStoreError = require('./errors/EdgeStoreError.js');
|
|
4
6
|
|
|
5
|
-
var zod = require('zod');
|
|
6
7
|
|
|
7
|
-
function _define_property$1(obj, key, value) {
|
|
8
|
-
if (key in obj) {
|
|
9
|
-
Object.defineProperty(obj, key, {
|
|
10
|
-
value: value,
|
|
11
|
-
enumerable: true,
|
|
12
|
-
configurable: true,
|
|
13
|
-
writable: true
|
|
14
|
-
});
|
|
15
|
-
} else {
|
|
16
|
-
obj[key] = value;
|
|
17
|
-
}
|
|
18
|
-
return obj;
|
|
19
|
-
}
|
|
20
|
-
/* eslint-disable @typescript-eslint/no-non-null-assertion */ const EDGE_STORE_ERROR_CODES = {
|
|
21
|
-
BAD_REQUEST: 400,
|
|
22
|
-
FILE_TOO_LARGE: 400,
|
|
23
|
-
MIME_TYPE_NOT_ALLOWED: 400,
|
|
24
|
-
UNAUTHORIZED: 401,
|
|
25
|
-
UPLOAD_NOT_ALLOWED: 403,
|
|
26
|
-
DELETE_NOT_ALLOWED: 403,
|
|
27
|
-
CREATE_CONTEXT_ERROR: 500,
|
|
28
|
-
SERVER_ERROR: 500
|
|
29
|
-
};
|
|
30
|
-
class EdgeStoreError extends Error {
|
|
31
|
-
formattedMessage() {
|
|
32
|
-
return `${this.message}${this.details ? `\n Details: ${JSON.stringify(this.details)}` : ''}${this.cause ? `\n Caused by: ${this.cause.message}` : ''}`;
|
|
33
|
-
}
|
|
34
|
-
formattedJson() {
|
|
35
|
-
return {
|
|
36
|
-
message: this.code === 'SERVER_ERROR' ? 'Internal server error' : this.message,
|
|
37
|
-
code: this.code,
|
|
38
|
-
details: this.details
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
constructor(opts){
|
|
42
|
-
super(opts.message);
|
|
43
|
-
_define_property$1(this, "cause", void 0);
|
|
44
|
-
_define_property$1(this, "code", void 0);
|
|
45
|
-
_define_property$1(this, "level", void 0);
|
|
46
|
-
_define_property$1(this, "details", void 0);
|
|
47
|
-
this.name = 'EdgeStoreError';
|
|
48
|
-
this.code = opts.code;
|
|
49
|
-
this.cause = opts.cause;
|
|
50
|
-
this.level = EDGE_STORE_ERROR_CODES[opts.code] >= 500 ? 'error' : 'warn';
|
|
51
|
-
this.details = 'details' in opts ? opts.details : undefined;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
8
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
enumerable: true,
|
|
60
|
-
configurable: true,
|
|
61
|
-
writable: true
|
|
62
|
-
});
|
|
63
|
-
} else {
|
|
64
|
-
obj[key] = value;
|
|
65
|
-
}
|
|
66
|
-
return obj;
|
|
67
|
-
}
|
|
68
|
-
class EdgeStoreApiClientError extends Error {
|
|
69
|
-
constructor(opts){
|
|
70
|
-
super(opts.response.message);
|
|
71
|
-
_define_property(this, "data", void 0);
|
|
72
|
-
this.name = 'EdgeStoreApiClientError';
|
|
73
|
-
this.data = opts.response;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Creates a Proxy that prints the path to the property when called.
|
|
79
|
-
*
|
|
80
|
-
* Example:
|
|
81
|
-
*
|
|
82
|
-
* ```ts
|
|
83
|
-
* const pathParamProxy = createPathParamProxy();
|
|
84
|
-
* console.log(pathParamProxy.ctx.user.id());
|
|
85
|
-
* // Logs: "ctx.user.id"
|
|
86
|
-
* console.log(pathParamProxy.input.type());
|
|
87
|
-
* // Logs: "input.type"
|
|
88
|
-
* ```
|
|
89
|
-
*/ function createPathParamProxy() {
|
|
90
|
-
const getPath = (target, _prop)=>{
|
|
91
|
-
const proxyFunction = ()=>target;
|
|
92
|
-
return new Proxy(proxyFunction, {
|
|
93
|
-
get: (_target, propChild)=>{
|
|
94
|
-
return getPath(`${target}.${String(propChild)}`);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
};
|
|
98
|
-
return new Proxy(()=>'', {
|
|
99
|
-
get: (_target, prop)=>{
|
|
100
|
-
return getPath(String(prop));
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const createNewBuilder = (initDef, newDef)=>{
|
|
106
|
-
const mergedDef = {
|
|
107
|
-
...initDef,
|
|
108
|
-
...newDef
|
|
109
|
-
};
|
|
110
|
-
return createBuilder({
|
|
111
|
-
type: mergedDef.type
|
|
112
|
-
}, mergedDef);
|
|
113
|
-
};
|
|
114
|
-
function createBuilder(opts, initDef) {
|
|
115
|
-
const _def = {
|
|
116
|
-
type: opts.type,
|
|
117
|
-
input: zod.z.never(),
|
|
118
|
-
path: [],
|
|
119
|
-
metadata: ()=>({}),
|
|
120
|
-
...initDef
|
|
121
|
-
};
|
|
122
|
-
return {
|
|
123
|
-
$config: {
|
|
124
|
-
ctx: undefined
|
|
125
|
-
},
|
|
126
|
-
// @ts-expect-error - I think it would be too much work to make this type correct.
|
|
127
|
-
_def,
|
|
128
|
-
input (input) {
|
|
129
|
-
return createNewBuilder(_def, {
|
|
130
|
-
input
|
|
131
|
-
});
|
|
132
|
-
},
|
|
133
|
-
path (pathResolver) {
|
|
134
|
-
// TODO: Should throw a runtime error in the following cases:
|
|
135
|
-
// 1. in case of multiple keys in one object
|
|
136
|
-
// 2. in case of duplicate keys
|
|
137
|
-
const pathParamProxy = createPathParamProxy();
|
|
138
|
-
const params = pathResolver(pathParamProxy);
|
|
139
|
-
return createNewBuilder(_def, {
|
|
140
|
-
path: params
|
|
141
|
-
});
|
|
142
|
-
},
|
|
143
|
-
metadata (metadata) {
|
|
144
|
-
return createNewBuilder(_def, {
|
|
145
|
-
metadata
|
|
146
|
-
});
|
|
147
|
-
},
|
|
148
|
-
accessControl (accessControl) {
|
|
149
|
-
return createNewBuilder(_def, {
|
|
150
|
-
accessControl: accessControl
|
|
151
|
-
});
|
|
152
|
-
},
|
|
153
|
-
beforeUpload (beforeUpload) {
|
|
154
|
-
return createNewBuilder(_def, {
|
|
155
|
-
beforeUpload
|
|
156
|
-
});
|
|
157
|
-
},
|
|
158
|
-
beforeDelete (beforeDelete) {
|
|
159
|
-
return createNewBuilder(_def, {
|
|
160
|
-
beforeDelete
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
class EdgeStoreBuilder {
|
|
166
|
-
context() {
|
|
167
|
-
return new EdgeStoreBuilder();
|
|
168
|
-
}
|
|
169
|
-
create() {
|
|
170
|
-
return createEdgeStoreInner()();
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
function createRouterFactory() {
|
|
174
|
-
return function createRouterInner(buckets) {
|
|
175
|
-
return {
|
|
176
|
-
$config: {
|
|
177
|
-
ctx: undefined
|
|
178
|
-
},
|
|
179
|
-
buckets
|
|
180
|
-
};
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
function initBucket(type, config) {
|
|
184
|
-
return createBuilder({
|
|
185
|
-
type
|
|
186
|
-
}, {
|
|
187
|
-
bucketConfig: config
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
function createEdgeStoreInner() {
|
|
191
|
-
return function initEdgeStoreInner() {
|
|
192
|
-
return {
|
|
193
|
-
/**
|
|
194
|
-
* Builder object for creating an image bucket
|
|
195
|
-
*/ imageBucket (config) {
|
|
196
|
-
return initBucket('IMAGE', config);
|
|
197
|
-
},
|
|
198
|
-
/**
|
|
199
|
-
* Builder object for creating a file bucket
|
|
200
|
-
*/ fileBucket (config) {
|
|
201
|
-
return initBucket('FILE', config);
|
|
202
|
-
},
|
|
203
|
-
/**
|
|
204
|
-
* Create a router
|
|
205
|
-
*/ router: createRouterFactory()
|
|
206
|
-
};
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Initialize EdgeStore - be done exactly once per backend
|
|
211
|
-
*/ const initEdgeStore = new EdgeStoreBuilder(); // ↓↓↓ TYPE TESTS ↓↓↓
|
|
212
|
-
// type Context = {
|
|
213
|
-
// userId: string;
|
|
214
|
-
// userRole: 'admin' | 'visitor';
|
|
215
|
-
// };
|
|
216
|
-
// const es = initEdgeStore.context<Context>().create();
|
|
217
|
-
// const imagesBucket = es.imageBucket()
|
|
218
|
-
// .input(
|
|
219
|
-
// z.object({
|
|
220
|
-
// type: z.enum(['profile', 'post']),
|
|
221
|
-
// extension: z.string().optional(),
|
|
222
|
-
// }),
|
|
223
|
-
// )
|
|
224
|
-
// .path(({ ctx, input }) => [{ author: ctx.userId }, { type: input.type }])
|
|
225
|
-
// .metadata(({ ctx, input }) => ({
|
|
226
|
-
// extension: input.extension,
|
|
227
|
-
// role: ctx.userRole,
|
|
228
|
-
// }))
|
|
229
|
-
// .beforeUpload(() => {
|
|
230
|
-
// return true;
|
|
231
|
-
// });
|
|
232
|
-
// const a = es.imageBucket()
|
|
233
|
-
// .input(z.object({ type: z.string(), someMeta: z.string().optional() }))
|
|
234
|
-
// .path(({ ctx, input }) => [{ author: ctx.userId }, { type: input.type }])
|
|
235
|
-
// .metadata(({ ctx, input }) => ({
|
|
236
|
-
// role: ctx.userRole,
|
|
237
|
-
// someMeta: input.someMeta,
|
|
238
|
-
// }))
|
|
239
|
-
// .accessControl({
|
|
240
|
-
// OR: [
|
|
241
|
-
// {
|
|
242
|
-
// userId: { path: 'author' }, // this will check if the userId is the same as the author in the path parameter
|
|
243
|
-
// },
|
|
244
|
-
// {
|
|
245
|
-
// userRole: 'admin', // this is the same as { userRole: { eq: "admin" } }
|
|
246
|
-
// },
|
|
247
|
-
// ],
|
|
248
|
-
// })
|
|
249
|
-
// .beforeUpload(({ ctx, input }) => {
|
|
250
|
-
// return true;
|
|
251
|
-
// })
|
|
252
|
-
// .beforeDelete(({ ctx, file }) => {
|
|
253
|
-
// return true;
|
|
254
|
-
// });
|
|
255
|
-
// const b = es.imageBucket().path(({ ctx }) => [{ author: ctx.userId }]);
|
|
256
|
-
// const router = es.router({
|
|
257
|
-
// original: imagesBucket,
|
|
258
|
-
// imageBucket: a,
|
|
259
|
-
// imageBucket2: b,
|
|
260
|
-
// });
|
|
261
|
-
// export { router };
|
|
262
|
-
// type ListFilesResponse<TBucket extends AnyRouter['buckets'][string]> = {
|
|
263
|
-
// data: {
|
|
264
|
-
// // url: string;
|
|
265
|
-
// // size: number;
|
|
266
|
-
// // uploadedAt: Date;
|
|
267
|
-
// // metadata: InferMetadataObject<TBucket>;
|
|
268
|
-
// path: InferBucketPathKeys<TBucket> extends string ? {
|
|
269
|
-
// [key: string]: string;
|
|
270
|
-
// } :{
|
|
271
|
-
// [TKey in InferBucketPathKeys<TBucket>]: string;
|
|
272
|
-
// };
|
|
273
|
-
// }[];
|
|
274
|
-
// pagination: {
|
|
275
|
-
// currentPage: number;
|
|
276
|
-
// totalPages: number;
|
|
277
|
-
// totalCount: number;
|
|
278
|
-
// };
|
|
279
|
-
// };
|
|
280
|
-
// type TPathKeys = 'author' | 'type';
|
|
281
|
-
// type TPathKeys2 = InferBucketPathKeys<AnyBuilder>;
|
|
282
|
-
// type ObjectWithKeys<TKeys extends string> = {
|
|
283
|
-
// [TKey in TKeys]: string;
|
|
284
|
-
// };
|
|
285
|
-
// type Test1 = ObjectWithKeys<TPathKeys>;
|
|
286
|
-
// type Test2 = ObjectWithKeys<TPathKeys2>;
|
|
287
|
-
// type PathKeys = InferBucketPathKeys<typeof router.buckets.imageBucket>;
|
|
288
|
-
// type MetadataKeys = InferMetadataObject<typeof router.buckets.imageBucket>;
|
|
289
|
-
// type MyEdgeStoreRouter = typeof router;
|
|
290
|
-
// type MyAccessControl = AccessControlSchema<Context, AnyDef>;
|
|
291
|
-
|
|
292
|
-
exports.EDGE_STORE_ERROR_CODES = EDGE_STORE_ERROR_CODES;
|
|
293
|
-
exports.EdgeStoreApiClientError = EdgeStoreApiClientError;
|
|
294
|
-
exports.EdgeStoreError = EdgeStoreError;
|
|
295
|
-
exports.initEdgeStore = initEdgeStore;
|
|
9
|
+
exports.EdgeStoreApiClientError = index.EdgeStoreApiClientError;
|
|
10
|
+
exports.initEdgeStore = bucketBuilder.initEdgeStore;
|
|
11
|
+
exports.EDGE_STORE_ERROR_CODES = EdgeStoreError.EDGE_STORE_ERROR_CODES;
|
|
12
|
+
exports.EdgeStoreError = EdgeStoreError.EdgeStoreError;
|
package/dist/index.mjs
CHANGED
|
@@ -1,288 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
if (key in obj) {
|
|
5
|
-
Object.defineProperty(obj, key, {
|
|
6
|
-
value: value,
|
|
7
|
-
enumerable: true,
|
|
8
|
-
configurable: true,
|
|
9
|
-
writable: true
|
|
10
|
-
});
|
|
11
|
-
} else {
|
|
12
|
-
obj[key] = value;
|
|
13
|
-
}
|
|
14
|
-
return obj;
|
|
15
|
-
}
|
|
16
|
-
/* eslint-disable @typescript-eslint/no-non-null-assertion */ const EDGE_STORE_ERROR_CODES = {
|
|
17
|
-
BAD_REQUEST: 400,
|
|
18
|
-
FILE_TOO_LARGE: 400,
|
|
19
|
-
MIME_TYPE_NOT_ALLOWED: 400,
|
|
20
|
-
UNAUTHORIZED: 401,
|
|
21
|
-
UPLOAD_NOT_ALLOWED: 403,
|
|
22
|
-
DELETE_NOT_ALLOWED: 403,
|
|
23
|
-
CREATE_CONTEXT_ERROR: 500,
|
|
24
|
-
SERVER_ERROR: 500
|
|
25
|
-
};
|
|
26
|
-
class EdgeStoreError extends Error {
|
|
27
|
-
formattedMessage() {
|
|
28
|
-
return `${this.message}${this.details ? `\n Details: ${JSON.stringify(this.details)}` : ''}${this.cause ? `\n Caused by: ${this.cause.message}` : ''}`;
|
|
29
|
-
}
|
|
30
|
-
formattedJson() {
|
|
31
|
-
return {
|
|
32
|
-
message: this.code === 'SERVER_ERROR' ? 'Internal server error' : this.message,
|
|
33
|
-
code: this.code,
|
|
34
|
-
details: this.details
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
constructor(opts){
|
|
38
|
-
super(opts.message);
|
|
39
|
-
_define_property$1(this, "cause", void 0);
|
|
40
|
-
_define_property$1(this, "code", void 0);
|
|
41
|
-
_define_property$1(this, "level", void 0);
|
|
42
|
-
_define_property$1(this, "details", void 0);
|
|
43
|
-
this.name = 'EdgeStoreError';
|
|
44
|
-
this.code = opts.code;
|
|
45
|
-
this.cause = opts.cause;
|
|
46
|
-
this.level = EDGE_STORE_ERROR_CODES[opts.code] >= 500 ? 'error' : 'warn';
|
|
47
|
-
this.details = 'details' in opts ? opts.details : undefined;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function _define_property(obj, key, value) {
|
|
52
|
-
if (key in obj) {
|
|
53
|
-
Object.defineProperty(obj, key, {
|
|
54
|
-
value: value,
|
|
55
|
-
enumerable: true,
|
|
56
|
-
configurable: true,
|
|
57
|
-
writable: true
|
|
58
|
-
});
|
|
59
|
-
} else {
|
|
60
|
-
obj[key] = value;
|
|
61
|
-
}
|
|
62
|
-
return obj;
|
|
63
|
-
}
|
|
64
|
-
class EdgeStoreApiClientError extends Error {
|
|
65
|
-
constructor(opts){
|
|
66
|
-
super(opts.response.message);
|
|
67
|
-
_define_property(this, "data", void 0);
|
|
68
|
-
this.name = 'EdgeStoreApiClientError';
|
|
69
|
-
this.data = opts.response;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Creates a Proxy that prints the path to the property when called.
|
|
75
|
-
*
|
|
76
|
-
* Example:
|
|
77
|
-
*
|
|
78
|
-
* ```ts
|
|
79
|
-
* const pathParamProxy = createPathParamProxy();
|
|
80
|
-
* console.log(pathParamProxy.ctx.user.id());
|
|
81
|
-
* // Logs: "ctx.user.id"
|
|
82
|
-
* console.log(pathParamProxy.input.type());
|
|
83
|
-
* // Logs: "input.type"
|
|
84
|
-
* ```
|
|
85
|
-
*/ function createPathParamProxy() {
|
|
86
|
-
const getPath = (target, _prop)=>{
|
|
87
|
-
const proxyFunction = ()=>target;
|
|
88
|
-
return new Proxy(proxyFunction, {
|
|
89
|
-
get: (_target, propChild)=>{
|
|
90
|
-
return getPath(`${target}.${String(propChild)}`);
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
};
|
|
94
|
-
return new Proxy(()=>'', {
|
|
95
|
-
get: (_target, prop)=>{
|
|
96
|
-
return getPath(String(prop));
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const createNewBuilder = (initDef, newDef)=>{
|
|
102
|
-
const mergedDef = {
|
|
103
|
-
...initDef,
|
|
104
|
-
...newDef
|
|
105
|
-
};
|
|
106
|
-
return createBuilder({
|
|
107
|
-
type: mergedDef.type
|
|
108
|
-
}, mergedDef);
|
|
109
|
-
};
|
|
110
|
-
function createBuilder(opts, initDef) {
|
|
111
|
-
const _def = {
|
|
112
|
-
type: opts.type,
|
|
113
|
-
input: z.never(),
|
|
114
|
-
path: [],
|
|
115
|
-
metadata: ()=>({}),
|
|
116
|
-
...initDef
|
|
117
|
-
};
|
|
118
|
-
return {
|
|
119
|
-
$config: {
|
|
120
|
-
ctx: undefined
|
|
121
|
-
},
|
|
122
|
-
// @ts-expect-error - I think it would be too much work to make this type correct.
|
|
123
|
-
_def,
|
|
124
|
-
input (input) {
|
|
125
|
-
return createNewBuilder(_def, {
|
|
126
|
-
input
|
|
127
|
-
});
|
|
128
|
-
},
|
|
129
|
-
path (pathResolver) {
|
|
130
|
-
// TODO: Should throw a runtime error in the following cases:
|
|
131
|
-
// 1. in case of multiple keys in one object
|
|
132
|
-
// 2. in case of duplicate keys
|
|
133
|
-
const pathParamProxy = createPathParamProxy();
|
|
134
|
-
const params = pathResolver(pathParamProxy);
|
|
135
|
-
return createNewBuilder(_def, {
|
|
136
|
-
path: params
|
|
137
|
-
});
|
|
138
|
-
},
|
|
139
|
-
metadata (metadata) {
|
|
140
|
-
return createNewBuilder(_def, {
|
|
141
|
-
metadata
|
|
142
|
-
});
|
|
143
|
-
},
|
|
144
|
-
accessControl (accessControl) {
|
|
145
|
-
return createNewBuilder(_def, {
|
|
146
|
-
accessControl: accessControl
|
|
147
|
-
});
|
|
148
|
-
},
|
|
149
|
-
beforeUpload (beforeUpload) {
|
|
150
|
-
return createNewBuilder(_def, {
|
|
151
|
-
beforeUpload
|
|
152
|
-
});
|
|
153
|
-
},
|
|
154
|
-
beforeDelete (beforeDelete) {
|
|
155
|
-
return createNewBuilder(_def, {
|
|
156
|
-
beforeDelete
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
class EdgeStoreBuilder {
|
|
162
|
-
context() {
|
|
163
|
-
return new EdgeStoreBuilder();
|
|
164
|
-
}
|
|
165
|
-
create() {
|
|
166
|
-
return createEdgeStoreInner()();
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
function createRouterFactory() {
|
|
170
|
-
return function createRouterInner(buckets) {
|
|
171
|
-
return {
|
|
172
|
-
$config: {
|
|
173
|
-
ctx: undefined
|
|
174
|
-
},
|
|
175
|
-
buckets
|
|
176
|
-
};
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
function initBucket(type, config) {
|
|
180
|
-
return createBuilder({
|
|
181
|
-
type
|
|
182
|
-
}, {
|
|
183
|
-
bucketConfig: config
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
function createEdgeStoreInner() {
|
|
187
|
-
return function initEdgeStoreInner() {
|
|
188
|
-
return {
|
|
189
|
-
/**
|
|
190
|
-
* Builder object for creating an image bucket
|
|
191
|
-
*/ imageBucket (config) {
|
|
192
|
-
return initBucket('IMAGE', config);
|
|
193
|
-
},
|
|
194
|
-
/**
|
|
195
|
-
* Builder object for creating a file bucket
|
|
196
|
-
*/ fileBucket (config) {
|
|
197
|
-
return initBucket('FILE', config);
|
|
198
|
-
},
|
|
199
|
-
/**
|
|
200
|
-
* Create a router
|
|
201
|
-
*/ router: createRouterFactory()
|
|
202
|
-
};
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Initialize EdgeStore - be done exactly once per backend
|
|
207
|
-
*/ const initEdgeStore = new EdgeStoreBuilder(); // ↓↓↓ TYPE TESTS ↓↓↓
|
|
208
|
-
// type Context = {
|
|
209
|
-
// userId: string;
|
|
210
|
-
// userRole: 'admin' | 'visitor';
|
|
211
|
-
// };
|
|
212
|
-
// const es = initEdgeStore.context<Context>().create();
|
|
213
|
-
// const imagesBucket = es.imageBucket()
|
|
214
|
-
// .input(
|
|
215
|
-
// z.object({
|
|
216
|
-
// type: z.enum(['profile', 'post']),
|
|
217
|
-
// extension: z.string().optional(),
|
|
218
|
-
// }),
|
|
219
|
-
// )
|
|
220
|
-
// .path(({ ctx, input }) => [{ author: ctx.userId }, { type: input.type }])
|
|
221
|
-
// .metadata(({ ctx, input }) => ({
|
|
222
|
-
// extension: input.extension,
|
|
223
|
-
// role: ctx.userRole,
|
|
224
|
-
// }))
|
|
225
|
-
// .beforeUpload(() => {
|
|
226
|
-
// return true;
|
|
227
|
-
// });
|
|
228
|
-
// const a = es.imageBucket()
|
|
229
|
-
// .input(z.object({ type: z.string(), someMeta: z.string().optional() }))
|
|
230
|
-
// .path(({ ctx, input }) => [{ author: ctx.userId }, { type: input.type }])
|
|
231
|
-
// .metadata(({ ctx, input }) => ({
|
|
232
|
-
// role: ctx.userRole,
|
|
233
|
-
// someMeta: input.someMeta,
|
|
234
|
-
// }))
|
|
235
|
-
// .accessControl({
|
|
236
|
-
// OR: [
|
|
237
|
-
// {
|
|
238
|
-
// userId: { path: 'author' }, // this will check if the userId is the same as the author in the path parameter
|
|
239
|
-
// },
|
|
240
|
-
// {
|
|
241
|
-
// userRole: 'admin', // this is the same as { userRole: { eq: "admin" } }
|
|
242
|
-
// },
|
|
243
|
-
// ],
|
|
244
|
-
// })
|
|
245
|
-
// .beforeUpload(({ ctx, input }) => {
|
|
246
|
-
// return true;
|
|
247
|
-
// })
|
|
248
|
-
// .beforeDelete(({ ctx, file }) => {
|
|
249
|
-
// return true;
|
|
250
|
-
// });
|
|
251
|
-
// const b = es.imageBucket().path(({ ctx }) => [{ author: ctx.userId }]);
|
|
252
|
-
// const router = es.router({
|
|
253
|
-
// original: imagesBucket,
|
|
254
|
-
// imageBucket: a,
|
|
255
|
-
// imageBucket2: b,
|
|
256
|
-
// });
|
|
257
|
-
// export { router };
|
|
258
|
-
// type ListFilesResponse<TBucket extends AnyRouter['buckets'][string]> = {
|
|
259
|
-
// data: {
|
|
260
|
-
// // url: string;
|
|
261
|
-
// // size: number;
|
|
262
|
-
// // uploadedAt: Date;
|
|
263
|
-
// // metadata: InferMetadataObject<TBucket>;
|
|
264
|
-
// path: InferBucketPathKeys<TBucket> extends string ? {
|
|
265
|
-
// [key: string]: string;
|
|
266
|
-
// } :{
|
|
267
|
-
// [TKey in InferBucketPathKeys<TBucket>]: string;
|
|
268
|
-
// };
|
|
269
|
-
// }[];
|
|
270
|
-
// pagination: {
|
|
271
|
-
// currentPage: number;
|
|
272
|
-
// totalPages: number;
|
|
273
|
-
// totalCount: number;
|
|
274
|
-
// };
|
|
275
|
-
// };
|
|
276
|
-
// type TPathKeys = 'author' | 'type';
|
|
277
|
-
// type TPathKeys2 = InferBucketPathKeys<AnyBuilder>;
|
|
278
|
-
// type ObjectWithKeys<TKeys extends string> = {
|
|
279
|
-
// [TKey in TKeys]: string;
|
|
280
|
-
// };
|
|
281
|
-
// type Test1 = ObjectWithKeys<TPathKeys>;
|
|
282
|
-
// type Test2 = ObjectWithKeys<TPathKeys2>;
|
|
283
|
-
// type PathKeys = InferBucketPathKeys<typeof router.buckets.imageBucket>;
|
|
284
|
-
// type MetadataKeys = InferMetadataObject<typeof router.buckets.imageBucket>;
|
|
285
|
-
// type MyEdgeStoreRouter = typeof router;
|
|
286
|
-
// type MyAccessControl = AccessControlSchema<Context, AnyDef>;
|
|
287
|
-
|
|
288
|
-
export { EDGE_STORE_ERROR_CODES, EdgeStoreApiClientError, EdgeStoreError, initEdgeStore };
|
|
1
|
+
export { EdgeStoreApiClientError } from './errors/index.mjs';
|
|
2
|
+
export { initEdgeStore } from './internals/bucketBuilder.mjs';
|
|
3
|
+
export { EDGE_STORE_ERROR_CODES, EdgeStoreError } from './errors/EdgeStoreError.mjs';
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var zod = require('zod');
|
|
4
|
+
var createPathParamProxy = require('./createPathParamProxy.js');
|
|
5
|
+
|
|
6
|
+
const createNewBuilder = (initDef, newDef)=>{
|
|
7
|
+
const mergedDef = {
|
|
8
|
+
...initDef,
|
|
9
|
+
...newDef
|
|
10
|
+
};
|
|
11
|
+
return createBuilder({
|
|
12
|
+
type: mergedDef.type
|
|
13
|
+
}, mergedDef);
|
|
14
|
+
};
|
|
15
|
+
function createBuilder(opts, initDef) {
|
|
16
|
+
const _def = {
|
|
17
|
+
type: opts.type,
|
|
18
|
+
input: zod.z.never(),
|
|
19
|
+
path: [],
|
|
20
|
+
metadata: ()=>({}),
|
|
21
|
+
...initDef
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
$config: {
|
|
25
|
+
ctx: undefined
|
|
26
|
+
},
|
|
27
|
+
// @ts-expect-error - I think it would be too much work to make this type correct.
|
|
28
|
+
_def,
|
|
29
|
+
input (input) {
|
|
30
|
+
return createNewBuilder(_def, {
|
|
31
|
+
input
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
path (pathResolver) {
|
|
35
|
+
// TODO: Should throw a runtime error in the following cases:
|
|
36
|
+
// 1. in case of multiple keys in one object
|
|
37
|
+
// 2. in case of duplicate keys
|
|
38
|
+
const pathParamProxy = createPathParamProxy.createPathParamProxy();
|
|
39
|
+
const params = pathResolver(pathParamProxy);
|
|
40
|
+
return createNewBuilder(_def, {
|
|
41
|
+
path: params
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
metadata (metadata) {
|
|
45
|
+
return createNewBuilder(_def, {
|
|
46
|
+
metadata
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
accessControl (accessControl) {
|
|
50
|
+
return createNewBuilder(_def, {
|
|
51
|
+
accessControl: accessControl
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
beforeUpload (beforeUpload) {
|
|
55
|
+
return createNewBuilder(_def, {
|
|
56
|
+
beforeUpload
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
beforeDelete (beforeDelete) {
|
|
60
|
+
return createNewBuilder(_def, {
|
|
61
|
+
beforeDelete
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
class EdgeStoreBuilder {
|
|
67
|
+
context() {
|
|
68
|
+
return new EdgeStoreBuilder();
|
|
69
|
+
}
|
|
70
|
+
create() {
|
|
71
|
+
return createEdgeStoreInner()();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function createRouterFactory() {
|
|
75
|
+
return function createRouterInner(buckets) {
|
|
76
|
+
return {
|
|
77
|
+
$config: {
|
|
78
|
+
ctx: undefined
|
|
79
|
+
},
|
|
80
|
+
buckets
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function initBucket(type, config) {
|
|
85
|
+
return createBuilder({
|
|
86
|
+
type
|
|
87
|
+
}, {
|
|
88
|
+
bucketConfig: config
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
function createEdgeStoreInner() {
|
|
92
|
+
return function initEdgeStoreInner() {
|
|
93
|
+
return {
|
|
94
|
+
/**
|
|
95
|
+
* Builder object for creating an image bucket
|
|
96
|
+
*/ imageBucket (config) {
|
|
97
|
+
return initBucket('IMAGE', config);
|
|
98
|
+
},
|
|
99
|
+
/**
|
|
100
|
+
* Builder object for creating a file bucket
|
|
101
|
+
*/ fileBucket (config) {
|
|
102
|
+
return initBucket('FILE', config);
|
|
103
|
+
},
|
|
104
|
+
/**
|
|
105
|
+
* Create a router
|
|
106
|
+
*/ router: createRouterFactory()
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Initialize EdgeStore - be done exactly once per backend
|
|
112
|
+
*/ const initEdgeStore = new EdgeStoreBuilder(); // ↓↓↓ TYPE TESTS ↓↓↓
|
|
113
|
+
// type Context = {
|
|
114
|
+
// userId: string;
|
|
115
|
+
// userRole: 'admin' | 'visitor';
|
|
116
|
+
// };
|
|
117
|
+
// const es = initEdgeStore.context<Context>().create();
|
|
118
|
+
// const imagesBucket = es.imageBucket()
|
|
119
|
+
// .input(
|
|
120
|
+
// z.object({
|
|
121
|
+
// type: z.enum(['profile', 'post']),
|
|
122
|
+
// extension: z.string().optional(),
|
|
123
|
+
// }),
|
|
124
|
+
// )
|
|
125
|
+
// .path(({ ctx, input }) => [{ author: ctx.userId }, { type: input.type }])
|
|
126
|
+
// .metadata(({ ctx, input }) => ({
|
|
127
|
+
// extension: input.extension,
|
|
128
|
+
// role: ctx.userRole,
|
|
129
|
+
// }))
|
|
130
|
+
// .beforeUpload(() => {
|
|
131
|
+
// return true;
|
|
132
|
+
// });
|
|
133
|
+
// const a = es.imageBucket()
|
|
134
|
+
// .input(z.object({ type: z.string(), someMeta: z.string().optional() }))
|
|
135
|
+
// .path(({ ctx, input }) => [{ author: ctx.userId }, { type: input.type }])
|
|
136
|
+
// .metadata(({ ctx, input }) => ({
|
|
137
|
+
// role: ctx.userRole,
|
|
138
|
+
// someMeta: input.someMeta,
|
|
139
|
+
// }))
|
|
140
|
+
// .accessControl({
|
|
141
|
+
// OR: [
|
|
142
|
+
// {
|
|
143
|
+
// userId: { path: 'author' }, // this will check if the userId is the same as the author in the path parameter
|
|
144
|
+
// },
|
|
145
|
+
// {
|
|
146
|
+
// userRole: 'admin', // this is the same as { userRole: { eq: "admin" } }
|
|
147
|
+
// },
|
|
148
|
+
// ],
|
|
149
|
+
// })
|
|
150
|
+
// .beforeUpload(({ ctx, input }) => {
|
|
151
|
+
// return true;
|
|
152
|
+
// })
|
|
153
|
+
// .beforeDelete(({ ctx, file }) => {
|
|
154
|
+
// return true;
|
|
155
|
+
// });
|
|
156
|
+
// const b = es.imageBucket().path(({ ctx }) => [{ author: ctx.userId }]);
|
|
157
|
+
// const router = es.router({
|
|
158
|
+
// original: imagesBucket,
|
|
159
|
+
// imageBucket: a,
|
|
160
|
+
// imageBucket2: b,
|
|
161
|
+
// });
|
|
162
|
+
// export { router };
|
|
163
|
+
// type ListFilesResponse<TBucket extends AnyRouter['buckets'][string]> = {
|
|
164
|
+
// data: {
|
|
165
|
+
// // url: string;
|
|
166
|
+
// // size: number;
|
|
167
|
+
// // uploadedAt: Date;
|
|
168
|
+
// // metadata: InferMetadataObject<TBucket>;
|
|
169
|
+
// path: InferBucketPathKeys<TBucket> extends string ? {
|
|
170
|
+
// [key: string]: string;
|
|
171
|
+
// } :{
|
|
172
|
+
// [TKey in InferBucketPathKeys<TBucket>]: string;
|
|
173
|
+
// };
|
|
174
|
+
// }[];
|
|
175
|
+
// pagination: {
|
|
176
|
+
// currentPage: number;
|
|
177
|
+
// totalPages: number;
|
|
178
|
+
// totalCount: number;
|
|
179
|
+
// };
|
|
180
|
+
// };
|
|
181
|
+
// type TPathKeys = 'author' | 'type';
|
|
182
|
+
// type TPathKeys2 = InferBucketPathKeys<AnyBuilder>;
|
|
183
|
+
// type ObjectWithKeys<TKeys extends string> = {
|
|
184
|
+
// [TKey in TKeys]: string;
|
|
185
|
+
// };
|
|
186
|
+
// type Test1 = ObjectWithKeys<TPathKeys>;
|
|
187
|
+
// type Test2 = ObjectWithKeys<TPathKeys2>;
|
|
188
|
+
// type PathKeys = InferBucketPathKeys<typeof router.buckets.imageBucket>;
|
|
189
|
+
// type MetadataKeys = InferMetadataObject<typeof router.buckets.imageBucket>;
|
|
190
|
+
// type MyEdgeStoreRouter = typeof router;
|
|
191
|
+
// type MyAccessControl = AccessControlSchema<Context, AnyDef>;
|
|
192
|
+
|
|
193
|
+
exports.initEdgeStore = initEdgeStore;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createPathParamProxy } from './createPathParamProxy.mjs';
|
|
3
|
+
|
|
4
|
+
const createNewBuilder = (initDef, newDef)=>{
|
|
5
|
+
const mergedDef = {
|
|
6
|
+
...initDef,
|
|
7
|
+
...newDef
|
|
8
|
+
};
|
|
9
|
+
return createBuilder({
|
|
10
|
+
type: mergedDef.type
|
|
11
|
+
}, mergedDef);
|
|
12
|
+
};
|
|
13
|
+
function createBuilder(opts, initDef) {
|
|
14
|
+
const _def = {
|
|
15
|
+
type: opts.type,
|
|
16
|
+
input: z.never(),
|
|
17
|
+
path: [],
|
|
18
|
+
metadata: ()=>({}),
|
|
19
|
+
...initDef
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
$config: {
|
|
23
|
+
ctx: undefined
|
|
24
|
+
},
|
|
25
|
+
// @ts-expect-error - I think it would be too much work to make this type correct.
|
|
26
|
+
_def,
|
|
27
|
+
input (input) {
|
|
28
|
+
return createNewBuilder(_def, {
|
|
29
|
+
input
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
path (pathResolver) {
|
|
33
|
+
// TODO: Should throw a runtime error in the following cases:
|
|
34
|
+
// 1. in case of multiple keys in one object
|
|
35
|
+
// 2. in case of duplicate keys
|
|
36
|
+
const pathParamProxy = createPathParamProxy();
|
|
37
|
+
const params = pathResolver(pathParamProxy);
|
|
38
|
+
return createNewBuilder(_def, {
|
|
39
|
+
path: params
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
metadata (metadata) {
|
|
43
|
+
return createNewBuilder(_def, {
|
|
44
|
+
metadata
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
accessControl (accessControl) {
|
|
48
|
+
return createNewBuilder(_def, {
|
|
49
|
+
accessControl: accessControl
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
beforeUpload (beforeUpload) {
|
|
53
|
+
return createNewBuilder(_def, {
|
|
54
|
+
beforeUpload
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
beforeDelete (beforeDelete) {
|
|
58
|
+
return createNewBuilder(_def, {
|
|
59
|
+
beforeDelete
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
class EdgeStoreBuilder {
|
|
65
|
+
context() {
|
|
66
|
+
return new EdgeStoreBuilder();
|
|
67
|
+
}
|
|
68
|
+
create() {
|
|
69
|
+
return createEdgeStoreInner()();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function createRouterFactory() {
|
|
73
|
+
return function createRouterInner(buckets) {
|
|
74
|
+
return {
|
|
75
|
+
$config: {
|
|
76
|
+
ctx: undefined
|
|
77
|
+
},
|
|
78
|
+
buckets
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function initBucket(type, config) {
|
|
83
|
+
return createBuilder({
|
|
84
|
+
type
|
|
85
|
+
}, {
|
|
86
|
+
bucketConfig: config
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function createEdgeStoreInner() {
|
|
90
|
+
return function initEdgeStoreInner() {
|
|
91
|
+
return {
|
|
92
|
+
/**
|
|
93
|
+
* Builder object for creating an image bucket
|
|
94
|
+
*/ imageBucket (config) {
|
|
95
|
+
return initBucket('IMAGE', config);
|
|
96
|
+
},
|
|
97
|
+
/**
|
|
98
|
+
* Builder object for creating a file bucket
|
|
99
|
+
*/ fileBucket (config) {
|
|
100
|
+
return initBucket('FILE', config);
|
|
101
|
+
},
|
|
102
|
+
/**
|
|
103
|
+
* Create a router
|
|
104
|
+
*/ router: createRouterFactory()
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Initialize EdgeStore - be done exactly once per backend
|
|
110
|
+
*/ const initEdgeStore = new EdgeStoreBuilder(); // ↓↓↓ TYPE TESTS ↓↓↓
|
|
111
|
+
// type Context = {
|
|
112
|
+
// userId: string;
|
|
113
|
+
// userRole: 'admin' | 'visitor';
|
|
114
|
+
// };
|
|
115
|
+
// const es = initEdgeStore.context<Context>().create();
|
|
116
|
+
// const imagesBucket = es.imageBucket()
|
|
117
|
+
// .input(
|
|
118
|
+
// z.object({
|
|
119
|
+
// type: z.enum(['profile', 'post']),
|
|
120
|
+
// extension: z.string().optional(),
|
|
121
|
+
// }),
|
|
122
|
+
// )
|
|
123
|
+
// .path(({ ctx, input }) => [{ author: ctx.userId }, { type: input.type }])
|
|
124
|
+
// .metadata(({ ctx, input }) => ({
|
|
125
|
+
// extension: input.extension,
|
|
126
|
+
// role: ctx.userRole,
|
|
127
|
+
// }))
|
|
128
|
+
// .beforeUpload(() => {
|
|
129
|
+
// return true;
|
|
130
|
+
// });
|
|
131
|
+
// const a = es.imageBucket()
|
|
132
|
+
// .input(z.object({ type: z.string(), someMeta: z.string().optional() }))
|
|
133
|
+
// .path(({ ctx, input }) => [{ author: ctx.userId }, { type: input.type }])
|
|
134
|
+
// .metadata(({ ctx, input }) => ({
|
|
135
|
+
// role: ctx.userRole,
|
|
136
|
+
// someMeta: input.someMeta,
|
|
137
|
+
// }))
|
|
138
|
+
// .accessControl({
|
|
139
|
+
// OR: [
|
|
140
|
+
// {
|
|
141
|
+
// userId: { path: 'author' }, // this will check if the userId is the same as the author in the path parameter
|
|
142
|
+
// },
|
|
143
|
+
// {
|
|
144
|
+
// userRole: 'admin', // this is the same as { userRole: { eq: "admin" } }
|
|
145
|
+
// },
|
|
146
|
+
// ],
|
|
147
|
+
// })
|
|
148
|
+
// .beforeUpload(({ ctx, input }) => {
|
|
149
|
+
// return true;
|
|
150
|
+
// })
|
|
151
|
+
// .beforeDelete(({ ctx, file }) => {
|
|
152
|
+
// return true;
|
|
153
|
+
// });
|
|
154
|
+
// const b = es.imageBucket().path(({ ctx }) => [{ author: ctx.userId }]);
|
|
155
|
+
// const router = es.router({
|
|
156
|
+
// original: imagesBucket,
|
|
157
|
+
// imageBucket: a,
|
|
158
|
+
// imageBucket2: b,
|
|
159
|
+
// });
|
|
160
|
+
// export { router };
|
|
161
|
+
// type ListFilesResponse<TBucket extends AnyRouter['buckets'][string]> = {
|
|
162
|
+
// data: {
|
|
163
|
+
// // url: string;
|
|
164
|
+
// // size: number;
|
|
165
|
+
// // uploadedAt: Date;
|
|
166
|
+
// // metadata: InferMetadataObject<TBucket>;
|
|
167
|
+
// path: InferBucketPathKeys<TBucket> extends string ? {
|
|
168
|
+
// [key: string]: string;
|
|
169
|
+
// } :{
|
|
170
|
+
// [TKey in InferBucketPathKeys<TBucket>]: string;
|
|
171
|
+
// };
|
|
172
|
+
// }[];
|
|
173
|
+
// pagination: {
|
|
174
|
+
// currentPage: number;
|
|
175
|
+
// totalPages: number;
|
|
176
|
+
// totalCount: number;
|
|
177
|
+
// };
|
|
178
|
+
// };
|
|
179
|
+
// type TPathKeys = 'author' | 'type';
|
|
180
|
+
// type TPathKeys2 = InferBucketPathKeys<AnyBuilder>;
|
|
181
|
+
// type ObjectWithKeys<TKeys extends string> = {
|
|
182
|
+
// [TKey in TKeys]: string;
|
|
183
|
+
// };
|
|
184
|
+
// type Test1 = ObjectWithKeys<TPathKeys>;
|
|
185
|
+
// type Test2 = ObjectWithKeys<TPathKeys2>;
|
|
186
|
+
// type PathKeys = InferBucketPathKeys<typeof router.buckets.imageBucket>;
|
|
187
|
+
// type MetadataKeys = InferMetadataObject<typeof router.buckets.imageBucket>;
|
|
188
|
+
// type MyEdgeStoreRouter = typeof router;
|
|
189
|
+
// type MyAccessControl = AccessControlSchema<Context, AnyDef>;
|
|
190
|
+
|
|
191
|
+
export { initEdgeStore };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates a Proxy that prints the path to the property when called.
|
|
5
|
+
*
|
|
6
|
+
* Example:
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* const pathParamProxy = createPathParamProxy();
|
|
10
|
+
* console.log(pathParamProxy.ctx.user.id());
|
|
11
|
+
* // Logs: "ctx.user.id"
|
|
12
|
+
* console.log(pathParamProxy.input.type());
|
|
13
|
+
* // Logs: "input.type"
|
|
14
|
+
* ```
|
|
15
|
+
*/ function createPathParamProxy() {
|
|
16
|
+
const getPath = (target, _prop)=>{
|
|
17
|
+
const proxyFunction = ()=>target;
|
|
18
|
+
return new Proxy(proxyFunction, {
|
|
19
|
+
get: (_target, propChild)=>{
|
|
20
|
+
return getPath(`${target}.${String(propChild)}`);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
return new Proxy(()=>'', {
|
|
25
|
+
get: (_target, prop)=>{
|
|
26
|
+
return getPath(String(prop));
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
exports.createPathParamProxy = createPathParamProxy;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a Proxy that prints the path to the property when called.
|
|
3
|
+
*
|
|
4
|
+
* Example:
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* const pathParamProxy = createPathParamProxy();
|
|
8
|
+
* console.log(pathParamProxy.ctx.user.id());
|
|
9
|
+
* // Logs: "ctx.user.id"
|
|
10
|
+
* console.log(pathParamProxy.input.type());
|
|
11
|
+
* // Logs: "input.type"
|
|
12
|
+
* ```
|
|
13
|
+
*/ function createPathParamProxy() {
|
|
14
|
+
const getPath = (target, _prop)=>{
|
|
15
|
+
const proxyFunction = ()=>target;
|
|
16
|
+
return new Proxy(proxyFunction, {
|
|
17
|
+
get: (_target, propChild)=>{
|
|
18
|
+
return getPath(`${target}.${String(propChild)}`);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
return new Proxy(()=>'', {
|
|
23
|
+
get: (_target, prop)=>{
|
|
24
|
+
return getPath(String(prop));
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export { createPathParamProxy };
|
package/package.json
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edgestore/shared",
|
|
3
|
-
"version": "0.6.0
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Upload files with ease from React/Next.js",
|
|
5
5
|
"homepage": "https://edgestore.dev",
|
|
6
|
-
"
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/edgestorejs/edgestore.git",
|
|
11
|
+
"directory": "packages/shared"
|
|
12
|
+
},
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
7
16
|
"author": "Ravi <me@ravi.com>",
|
|
8
17
|
"main": "dist/index.js",
|
|
9
18
|
"module": "dist/index.mjs",
|
|
10
|
-
"
|
|
19
|
+
"types": "dist/index.d.ts",
|
|
11
20
|
"keywords": [
|
|
12
21
|
"react",
|
|
13
22
|
"nodejs",
|
|
@@ -33,13 +42,9 @@
|
|
|
33
42
|
"README.md",
|
|
34
43
|
"LICENSE",
|
|
35
44
|
"package.json",
|
|
36
|
-
"!**/*.test.*"
|
|
45
|
+
"!**/*.test.*",
|
|
46
|
+
"!**/__tests__"
|
|
37
47
|
],
|
|
38
|
-
"private": false,
|
|
39
|
-
"publishConfig": {
|
|
40
|
-
"access": "public"
|
|
41
|
-
},
|
|
42
|
-
"license": "MIT",
|
|
43
48
|
"peerDependencies": {
|
|
44
49
|
"react": ">=16.8.0",
|
|
45
50
|
"react-dom": ">=16.8.0",
|