@edge-store/server
Version:
Image Handling for React/Next.js
167 lines (163 loc) • 4.57 kB
JavaScript
import { z } from 'zod';
/**
* Creates a Proxy that prints the path to the property when called.
*
* Example:
*
* ```ts
* const pathParamProxy = createPathParamProxy();
* console.log(pathParamProxy.ctx.user.id());
* // Logs: "ctx.user.id"
* console.log(pathParamProxy.input.type());
* // Logs: "input.type"
* ```
*/ function createPathParamProxy() {
const getPath = (target, _prop)=>{
const proxyFunction = ()=>target;
return new Proxy(proxyFunction, {
get: (_target, propChild)=>{
return getPath(`${target}.${String(propChild)}`);
}
});
};
return new Proxy(()=>'', {
get: (_target, prop)=>{
return getPath(String(prop));
}
});
}
const createNewBuilder = (initDef, newDef)=>{
const mergedDef = {
...initDef,
...newDef
};
return createBuilder({
type: mergedDef.type
}, mergedDef);
};
function createBuilder(opts, initDef) {
const _def = {
type: opts.type,
input: z.never(),
path: [],
...initDef
};
return {
_def,
input (input) {
return createNewBuilder(_def, {
input
});
},
path (pathResolver) {
// TODO: Should throw a runtime error in the followin cases:
// 1. in case of multiple keys in one object
// 2. in case of duplicate keys
const pathParamProxy = createPathParamProxy();
const params = pathResolver(pathParamProxy);
return createNewBuilder(_def, {
path: params
});
},
metadata (metadata) {
return createNewBuilder(_def, {
metadata
});
},
accessControl (accessControl) {
return createNewBuilder(_def, {
accessControl: accessControl
});
},
beforeUpload (beforeUpload) {
return createNewBuilder(_def, {
beforeUpload
});
}
};
}
class EdgeStoreBuilder {
context() {
return new EdgeStoreBuilder();
}
create() {
return createEdgeStoreInner()();
}
}
function createRouterFactory() {
return function createRouterInner(routes) {
return {
routes
};
};
}
function createEdgeStoreInner() {
return function initEdgeStoreInner() {
return {
/**
* Builder object for creating an image bucket
*/ imageBucket: createBuilder({
type: 'IMAGE'
}),
/**
* Builder object for creating a file bucket
*/ fileBucket: createBuilder({
type: 'FILE'
}),
/**
* Create a router
*/ router: createRouterFactory()
};
};
}
/**
* Initialize tRPC - be done exactly once per backend
*/ const initEdgeStore = new EdgeStoreBuilder(); // ↓↓↓ TYPE TESTS ↓↓↓
// type Context = {
// userId: string;
// userRole: "admin" | "visitor";
// };
// const es = initEdgeStore.context<Context>().create();
// const imagesBucket = es.imageBucket
// .input(
// z.object({
// type: z.enum(['profile', 'post']),
// extension: z.string().optional(),
// }),
// )
// .path(({ ctx, input }) => [{ author: ctx.userId }, { type: input.type }])
// .metadata(({ ctx, input }) => ({
// extension: input.extension,
// role: ctx.userRole,
// }))
// .beforeUpload(() => {
// return true;
// });
// const a = es.imageBucket
// .input(z.object({ type: z.string(), someMeta: z.string().optional() }))
// .path(({ ctx, input }) => [{ author: ctx.userId }, { type: input.type }])
// .metadata(({ ctx, input }) => ({
// role: ctx.userRole,
// someMeta: input.someMeta,
// }))
// .accessControl({
// OR: [
// {
// userId: { path: "author" }, // this will check if the userId is the same as the author in the path parameter
// },
// {
// userRole: "admin", // this is the same as { userRole: { eq: "admin" } }
// },
// ],
// })
// .beforeUpload(({ ctx, input }) => {
// return true;
// });
// const b = es.imageBucket.path(({ ctx }) => [{ author: ctx.userId }]);
// const router = es.router({
// imageBucket: a,
// imageBucket2: b,
// });
// type EdgeStoreRouter = typeof router;
// type MyAccessControl = AccessControlSchema<Context, AnyDef>;
export { initEdgeStore };