UNPKG

@edge-store/server

Version:

Image Handling for React/Next.js

167 lines (163 loc) 4.57 kB
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 };