@goscribe/server 1.0.0 → 1.0.2

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.
@@ -0,0 +1,9 @@
1
+ import type { CreateExpressContextOptions } from "@trpc/server/adapters/express";
2
+ export declare function createContext({ req, res }: CreateExpressContextOptions): Promise<{
3
+ db: import("src/generated/prisma").PrismaClient<import("src/generated/prisma").Prisma.PrismaClientOptions, never, import("src/generated/prisma/runtime/library").DefaultArgs>;
4
+ session: any;
5
+ req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
6
+ res: import("express").Response<any, Record<string, any>>;
7
+ }>;
8
+ export type Context = Awaited<ReturnType<typeof createContext>>;
9
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAGjF,wBAAsB,aAAa,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,2BAA2B;;;;;GAI5E;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createContext = createContext;
4
+ const prisma_1 = require("./lib/prisma");
5
+ async function createContext({ req, res }) {
6
+ const session = req.auth ?? null;
7
+ return { db: prisma_1.prisma, session, req, res };
8
+ }
@@ -0,0 +1,4 @@
1
+ export type { AppRouter } from "./routers/_app";
2
+ export type { RouterInputs } from "./routers/_app";
3
+ export type { RouterOutputs } from "./routers/_app";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ export declare const authRouter: (req: import("express").Request, res: import("express").Response, next: import("express").NextFunction) => Promise<void>;
2
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,UAAU,0HA0BnB,CAAA"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.authRouter = void 0;
7
+ // src/server/auth.ts
8
+ const express_1 = require("@auth/express");
9
+ const prisma_adapter_1 = require("@auth/prisma-adapter");
10
+ const prisma_1 = require("../lib/prisma");
11
+ const google_1 = __importDefault(require("@auth/core/providers/google"));
12
+ const credentials_1 = __importDefault(require("@auth/core/providers/credentials"));
13
+ exports.authRouter = (0, express_1.ExpressAuth)({
14
+ providers: [
15
+ (0, google_1.default)({
16
+ clientId: process.env.GOOGLE_CLIENT_ID,
17
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET,
18
+ }),
19
+ (0, credentials_1.default)({
20
+ name: "credentials",
21
+ credentials: {
22
+ email: { label: "Email", type: "email" },
23
+ password: { label: "Password", type: "password" },
24
+ },
25
+ async authorize(credentials) {
26
+ if (credentials?.email === "demo@example.com" &&
27
+ credentials?.password === "demo") {
28
+ return { id: "1", email: "demo@example.com", name: "Demo User" };
29
+ }
30
+ return null;
31
+ },
32
+ }),
33
+ ],
34
+ adapter: (0, prisma_adapter_1.PrismaAdapter)(prisma_1.prisma),
35
+ secret: process.env.AUTH_SECRET,
36
+ session: { strategy: "jwt" },
37
+ });
@@ -0,0 +1,3 @@
1
+ import { PrismaClient } from "../generated/prisma";
2
+ export declare const prisma: PrismaClient<import("../generated/prisma").Prisma.PrismaClientOptions, never, import("src/generated/prisma/runtime/library").DefaultArgs>;
3
+ //# sourceMappingURL=prisma.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma.d.ts","sourceRoot":"","sources":["../../src/lib/prisma.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAInD,eAAO,MAAM,MAAM,2IAIf,CAAC"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.prisma = void 0;
4
+ const prisma_1 = require("../generated/prisma");
5
+ const globalForPrisma = globalThis;
6
+ exports.prisma = globalForPrisma.prisma ??
7
+ new prisma_1.PrismaClient({
8
+ // log: ["query"], // enable if you want
9
+ });
10
+ if (process.env.NODE_ENV !== "production")
11
+ globalForPrisma.prisma = exports.prisma;
@@ -0,0 +1,99 @@
1
+ import { inferRouterInputs, inferRouterOutputs } from '@trpc/server';
2
+ export declare const appRouter: import("@trpc/server").TRPCBuiltRouter<{
3
+ ctx: {
4
+ db: import("src/generated/prisma").PrismaClient<import("src/generated/prisma").Prisma.PrismaClientOptions, never, import("src/generated/prisma/runtime/library").DefaultArgs>;
5
+ session: any;
6
+ req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
7
+ res: import("express").Response<any, Record<string, any>>;
8
+ };
9
+ meta: object;
10
+ errorShape: import("@trpc/server").TRPCDefaultErrorShape;
11
+ transformer: true;
12
+ }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
13
+ auth: import("@trpc/server").TRPCBuiltRouter<{
14
+ ctx: {
15
+ db: import("src/generated/prisma").PrismaClient<import("src/generated/prisma").Prisma.PrismaClientOptions, never, import("src/generated/prisma/runtime/library").DefaultArgs>;
16
+ session: any;
17
+ req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
18
+ res: import("express").Response<any, Record<string, any>>;
19
+ };
20
+ meta: object;
21
+ errorShape: import("@trpc/server").TRPCDefaultErrorShape;
22
+ transformer: true;
23
+ }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
24
+ signup: import("@trpc/server").TRPCMutationProcedure<{
25
+ input: {
26
+ name: string;
27
+ email: string;
28
+ password: string;
29
+ };
30
+ output: {
31
+ id: string;
32
+ email: string | null;
33
+ name: string | null;
34
+ };
35
+ meta: object;
36
+ }>;
37
+ }>>;
38
+ workspace: import("@trpc/server").TRPCBuiltRouter<{
39
+ ctx: {
40
+ db: import("src/generated/prisma").PrismaClient<import("src/generated/prisma").Prisma.PrismaClientOptions, never, import("src/generated/prisma/runtime/library").DefaultArgs>;
41
+ session: any;
42
+ req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
43
+ res: import("express").Response<any, Record<string, any>>;
44
+ };
45
+ meta: object;
46
+ errorShape: import("@trpc/server").TRPCDefaultErrorShape;
47
+ transformer: true;
48
+ }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
49
+ list: import("@trpc/server").TRPCQueryProcedure<{
50
+ input: void;
51
+ output: void;
52
+ meta: object;
53
+ }>;
54
+ create: import("@trpc/server").TRPCMutationProcedure<{
55
+ input: Record<string, never>;
56
+ output: void;
57
+ meta: object;
58
+ }>;
59
+ get: import("@trpc/server").TRPCQueryProcedure<{
60
+ input: {
61
+ id: string;
62
+ };
63
+ output: void;
64
+ meta: object;
65
+ }>;
66
+ update: import("@trpc/server").TRPCMutationProcedure<{
67
+ input: {
68
+ id: string;
69
+ };
70
+ output: void;
71
+ meta: object;
72
+ }>;
73
+ delete: import("@trpc/server").TRPCMutationProcedure<{
74
+ input: {
75
+ id: string;
76
+ };
77
+ output: void;
78
+ meta: object;
79
+ }>;
80
+ upload: import("@trpc/server").TRPCMutationProcedure<{
81
+ input: {
82
+ file: string;
83
+ };
84
+ output: void;
85
+ meta: object;
86
+ }>;
87
+ deleteFile: import("@trpc/server").TRPCMutationProcedure<{
88
+ input: {
89
+ fileId: string;
90
+ };
91
+ output: void;
92
+ meta: object;
93
+ }>;
94
+ }>>;
95
+ }>>;
96
+ export type AppRouter = typeof appRouter;
97
+ export type RouterInputs = inferRouterInputs<AppRouter>;
98
+ export type RouterOutputs = inferRouterOutputs<AppRouter>;
99
+ //# sourceMappingURL=_app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_app.d.ts","sourceRoot":"","sources":["../../src/routers/_app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAKrE,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAGpB,CAAC;AAGH,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC;AACzC,MAAM,MAAM,YAAY,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;AACxD,MAAM,MAAM,aAAa,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.appRouter = void 0;
4
+ const trpc_1 = require("../trpc");
5
+ const auth_1 = require("./auth");
6
+ const workspace_1 = require("./workspace");
7
+ exports.appRouter = (0, trpc_1.router)({
8
+ auth: auth_1.auth,
9
+ workspace: workspace_1.workspace
10
+ });
@@ -0,0 +1,26 @@
1
+ export declare const auth: import("@trpc/server").TRPCBuiltRouter<{
2
+ ctx: {
3
+ db: import("src/generated/prisma").PrismaClient<import("src/generated/prisma").Prisma.PrismaClientOptions, never, import("src/generated/prisma/runtime/library").DefaultArgs>;
4
+ session: any;
5
+ req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
6
+ res: import("express").Response<any, Record<string, any>>;
7
+ };
8
+ meta: object;
9
+ errorShape: import("@trpc/server").TRPCDefaultErrorShape;
10
+ transformer: true;
11
+ }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
12
+ signup: import("@trpc/server").TRPCMutationProcedure<{
13
+ input: {
14
+ name: string;
15
+ email: string;
16
+ password: string;
17
+ };
18
+ output: {
19
+ id: string;
20
+ email: string | null;
21
+ name: string | null;
22
+ };
23
+ meta: object;
24
+ }>;
25
+ }>>;
26
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/routers/auth.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;GA4Bf,CAAC"}
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.auth = void 0;
7
+ const zod_1 = require("zod");
8
+ const trpc_1 = require("../trpc");
9
+ const bcryptjs_1 = __importDefault(require("bcryptjs"));
10
+ exports.auth = (0, trpc_1.router)({
11
+ signup: trpc_1.publicProcedure
12
+ .input(zod_1.z.object({
13
+ name: zod_1.z.string().min(1),
14
+ email: zod_1.z.string().email(),
15
+ password: zod_1.z.string().min(6),
16
+ }))
17
+ .mutation(async ({ ctx, input }) => {
18
+ const existing = await ctx.db.user.findUnique({
19
+ where: { email: input.email },
20
+ });
21
+ if (existing) {
22
+ throw new Error("Email already registered");
23
+ }
24
+ const hash = await bcryptjs_1.default.hash(input.password, 10);
25
+ const user = await ctx.db.user.create({
26
+ data: {
27
+ name: input.name,
28
+ email: input.email,
29
+ passwordHash: hash,
30
+ emailVerified: new Date(), // skip verification for demo
31
+ },
32
+ });
33
+ return { id: user.id, email: user.email, name: user.name };
34
+ }),
35
+ });
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sampleRouter = void 0;
4
+ const zod_1 = require("zod");
5
+ const trpc_1 = require("../trpc");
6
+ exports.sampleRouter = (0, trpc_1.router)({
7
+ // GET-like: query without input
8
+ hello: trpc_1.publicProcedure.query(() => {
9
+ return { message: 'Hello from tRPC + Express 👋' };
10
+ }),
11
+ // Mutation with Zod input
12
+ echo: trpc_1.publicProcedure
13
+ .input(zod_1.z.object({ text: zod_1.z.string().min(1) }))
14
+ .mutation(({ input }) => {
15
+ return { echoed: input.text };
16
+ }),
17
+ // Authed query
18
+ me: trpc_1.authedProcedure.query(({ ctx }) => {
19
+ return { userId: ctx.user.id, role: ctx.user.role };
20
+ }),
21
+ });
@@ -0,0 +1,58 @@
1
+ export declare const workspace: import("@trpc/server").TRPCBuiltRouter<{
2
+ ctx: {
3
+ db: import("src/generated/prisma").PrismaClient<import("src/generated/prisma").Prisma.PrismaClientOptions, never, import("src/generated/prisma/runtime/library").DefaultArgs>;
4
+ session: any;
5
+ req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
6
+ res: import("express").Response<any, Record<string, any>>;
7
+ };
8
+ meta: object;
9
+ errorShape: import("@trpc/server").TRPCDefaultErrorShape;
10
+ transformer: true;
11
+ }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
12
+ list: import("@trpc/server").TRPCQueryProcedure<{
13
+ input: void;
14
+ output: void;
15
+ meta: object;
16
+ }>;
17
+ create: import("@trpc/server").TRPCMutationProcedure<{
18
+ input: Record<string, never>;
19
+ output: void;
20
+ meta: object;
21
+ }>;
22
+ get: import("@trpc/server").TRPCQueryProcedure<{
23
+ input: {
24
+ id: string;
25
+ };
26
+ output: void;
27
+ meta: object;
28
+ }>;
29
+ update: import("@trpc/server").TRPCMutationProcedure<{
30
+ input: {
31
+ id: string;
32
+ };
33
+ output: void;
34
+ meta: object;
35
+ }>;
36
+ delete: import("@trpc/server").TRPCMutationProcedure<{
37
+ input: {
38
+ id: string;
39
+ };
40
+ output: void;
41
+ meta: object;
42
+ }>;
43
+ upload: import("@trpc/server").TRPCMutationProcedure<{
44
+ input: {
45
+ file: string;
46
+ };
47
+ output: void;
48
+ meta: object;
49
+ }>;
50
+ deleteFile: import("@trpc/server").TRPCMutationProcedure<{
51
+ input: {
52
+ fileId: string;
53
+ };
54
+ output: void;
55
+ meta: object;
56
+ }>;
57
+ }>>;
58
+ //# sourceMappingURL=workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/routers/workspace.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CpB,CAAC"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.workspace = void 0;
4
+ const zod_1 = require("zod");
5
+ const trpc_1 = require("../trpc");
6
+ exports.workspace = (0, trpc_1.router)({
7
+ // Mutation with Zod input
8
+ list: trpc_1.publicProcedure
9
+ .query(async ({ ctx, input }) => {
10
+ }),
11
+ create: trpc_1.publicProcedure
12
+ .input(zod_1.z.object({}))
13
+ .mutation(({ input }) => {
14
+ }),
15
+ get: trpc_1.publicProcedure
16
+ .input(zod_1.z.object({
17
+ id: zod_1.z.string().uuid(),
18
+ }))
19
+ .query(({ input }) => {
20
+ }),
21
+ update: trpc_1.publicProcedure
22
+ .input(zod_1.z.object({
23
+ id: zod_1.z.string().uuid(),
24
+ }))
25
+ .mutation(({ input }) => {
26
+ }),
27
+ delete: trpc_1.publicProcedure
28
+ .input(zod_1.z.object({
29
+ id: zod_1.z.string().uuid(),
30
+ }))
31
+ .mutation(({ input }) => {
32
+ }),
33
+ upload: trpc_1.publicProcedure
34
+ .input(zod_1.z.object({
35
+ file: zod_1.z.string(),
36
+ }))
37
+ .mutation(({ input }) => {
38
+ }),
39
+ deleteFile: trpc_1.publicProcedure
40
+ .input(zod_1.z.object({
41
+ fileId: zod_1.z.string().uuid(),
42
+ }))
43
+ .mutation(({ input }) => {
44
+ }),
45
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":""}
package/dist/server.js ADDED
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const express_1 = __importDefault(require("express"));
40
+ const cors_1 = __importDefault(require("cors"));
41
+ const helmet_1 = __importDefault(require("helmet"));
42
+ const morgan_1 = __importDefault(require("morgan"));
43
+ const compression_1 = __importDefault(require("compression"));
44
+ const trpcExpress = __importStar(require("@trpc/server/adapters/express"));
45
+ const auth_1 = require("./lib/auth");
46
+ const _app_1 = require("./routers/_app");
47
+ const context_1 = require("./context");
48
+ const PORT = process.env.PORT ? Number(process.env.PORT) : 3001;
49
+ async function main() {
50
+ const app = (0, express_1.default)();
51
+ // Middlewares
52
+ app.use((0, helmet_1.default)());
53
+ app.use((0, cors_1.default)({ origin: true, credentials: true }));
54
+ app.use((0, morgan_1.default)('dev'));
55
+ app.use((0, compression_1.default)());
56
+ app.use(express_1.default.json());
57
+ app.use("/auth", auth_1.authRouter); // Auth routes live under /auth/*
58
+ // Health (plain Express)
59
+ app.get('/', (_req, res) => {
60
+ res.json({ ok: true, service: 'trpc-express', ts: Date.now() });
61
+ });
62
+ // tRPC mounted under /trpc
63
+ app.use('/trpc', trpcExpress.createExpressMiddleware({
64
+ router: _app_1.appRouter,
65
+ createContext: context_1.createContext,
66
+ }));
67
+ app.listen(PORT, () => {
68
+ console.log(`✅ Server ready on http://localhost:${PORT}`);
69
+ console.log(`➡️ tRPC endpoint at http://localhost:${PORT}/trpc`);
70
+ });
71
+ }
72
+ main().catch((err) => {
73
+ console.error('Failed to start server', err);
74
+ process.exit(1);
75
+ });
package/dist/trpc.d.ts ADDED
@@ -0,0 +1,41 @@
1
+ export declare const router: import("@trpc/server").TRPCRouterBuilder<{
2
+ ctx: {
3
+ db: import("src/generated/prisma").PrismaClient<import("src/generated/prisma").Prisma.PrismaClientOptions, never, import("src/generated/prisma/runtime/library").DefaultArgs>;
4
+ session: any;
5
+ req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
6
+ res: import("express").Response<any, Record<string, any>>;
7
+ };
8
+ meta: object;
9
+ errorShape: import("@trpc/server").TRPCDefaultErrorShape;
10
+ transformer: true;
11
+ }>;
12
+ export declare const middleware: <$ContextOverrides>(fn: import("@trpc/server").TRPCMiddlewareFunction<{
13
+ db: import("src/generated/prisma").PrismaClient<import("src/generated/prisma").Prisma.PrismaClientOptions, never, import("src/generated/prisma/runtime/library").DefaultArgs>;
14
+ session: any;
15
+ req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
16
+ res: import("express").Response<any, Record<string, any>>;
17
+ }, object, object, $ContextOverrides, unknown>) => import("@trpc/server").TRPCMiddlewareBuilder<{
18
+ db: import("src/generated/prisma").PrismaClient<import("src/generated/prisma").Prisma.PrismaClientOptions, never, import("src/generated/prisma/runtime/library").DefaultArgs>;
19
+ session: any;
20
+ req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
21
+ res: import("express").Response<any, Record<string, any>>;
22
+ }, object, $ContextOverrides, unknown>;
23
+ export declare const publicProcedure: import("@trpc/server").TRPCProcedureBuilder<{
24
+ db: import("src/generated/prisma").PrismaClient<import("src/generated/prisma").Prisma.PrismaClientOptions, never, import("src/generated/prisma/runtime/library").DefaultArgs>;
25
+ session: any;
26
+ req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
27
+ res: import("express").Response<any, Record<string, any>>;
28
+ }, object, object, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, false>;
29
+ /** Exported authed procedure */
30
+ export declare const authedProcedure: import("@trpc/server").TRPCProcedureBuilder<{
31
+ db: import("src/generated/prisma").PrismaClient<import("src/generated/prisma").Prisma.PrismaClientOptions, never, import("src/generated/prisma/runtime/library").DefaultArgs>;
32
+ session: any;
33
+ req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
34
+ res: import("express").Response<any, Record<string, any>>;
35
+ }, object, {
36
+ req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
37
+ res: import("express").Response<any, Record<string, any>>;
38
+ db: import("src/generated/prisma").PrismaClient<import("src/generated/prisma").Prisma.PrismaClientOptions, never, import("src/generated/prisma/runtime/library").DefaultArgs>;
39
+ session: any;
40
+ }, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, false>;
41
+ //# sourceMappingURL=trpc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trpc.d.ts","sourceRoot":"","sources":["../src/trpc.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,MAAM;;;;;;;;;;EAAW,CAAC;AAC/B,eAAO,MAAM,UAAU;;;;;;;;;;sCAAe,CAAC;AACvC,eAAO,MAAM,eAAe;;;;;yLAAc,CAAC;AAsB3C,gCAAgC;AAChC,eAAO,MAAM,eAAe;;;;;;;;;;yKAAgC,CAAC"}
package/dist/trpc.js ADDED
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.authedProcedure = exports.publicProcedure = exports.middleware = exports.router = void 0;
7
+ const server_1 = require("@trpc/server");
8
+ const superjson_1 = __importDefault(require("superjson"));
9
+ const t = server_1.initTRPC.context().create({
10
+ transformer: superjson_1.default,
11
+ errorFormatter({ shape }) {
12
+ return shape;
13
+ },
14
+ });
15
+ exports.router = t.router;
16
+ exports.middleware = t.middleware;
17
+ exports.publicProcedure = t.procedure;
18
+ /** Middleware that enforces authentication */
19
+ const isAuthed = (0, exports.middleware)(({ ctx, next }) => {
20
+ if (!ctx.session?.user?.id) {
21
+ throw new server_1.TRPCError({ code: "UNAUTHORIZED" });
22
+ }
23
+ return next({
24
+ ctx: {
25
+ ...ctx,
26
+ // refine ctx: session is guaranteed, user.id is string
27
+ session: {
28
+ ...ctx.session,
29
+ user: {
30
+ ...ctx.session.user,
31
+ id: ctx.session.user.id, // typed non-null
32
+ },
33
+ },
34
+ },
35
+ });
36
+ });
37
+ /** Exported authed procedure */
38
+ exports.authedProcedure = exports.publicProcedure.use(isAuthed);
package/package.json CHANGED
@@ -1,8 +1,15 @@
1
1
  {
2
2
  "name": "@goscribe/server",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "",
5
- "main": "index.js",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ }
12
+ },
6
13
  "scripts": {
7
14
  "dev": "ts-node-dev --respawn --transpile-only src/server.ts",
8
15
  "build": "tsc -p .",
@@ -140,8 +140,8 @@ model FileAsset {
140
140
  name String
141
141
  mimeType String
142
142
  size Int
143
- bucket String
144
- objectKey String
143
+ bucket String?
144
+ objectKey String?
145
145
  url String? // optional if serving via signed GET per-view
146
146
  checksum String? // optional server-side integrity
147
147
 
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export type { AppRouter } from "./routers/_app";
2
+ export type { RouterInputs } from "./routers/_app";
3
+ export type { RouterOutputs } from "./routers/_app";
File without changes
@@ -0,0 +1,13 @@
1
+ // src/server/lib/gcs.ts
2
+ import { Storage } from "@google-cloud/storage";
3
+
4
+ export const storage = new Storage({
5
+ projectId: process.env.GCP_PROJECT_ID,
6
+ credentials: {
7
+ client_email: process.env.GCP_CLIENT_EMAIL,
8
+ private_key: process.env.GCP_PRIVATE_KEY?.replace(/\\n/g, "\n"),
9
+ },
10
+ });
11
+
12
+ export const bucket = storage.bucket(process.env.GCP_BUCKET!);
13
+
@@ -1,3 +1,4 @@
1
+ import { inferRouterInputs, inferRouterOutputs } from '@trpc/server';
1
2
  import { router } from '../trpc';
2
3
  import { auth } from './auth';
3
4
  import { workspace } from './workspace';
@@ -9,3 +10,5 @@ export const appRouter = router({
9
10
 
10
11
  // Export type for client inference
11
12
  export type AppRouter = typeof appRouter;
13
+ export type RouterInputs = inferRouterInputs<AppRouter>;
14
+ export type RouterOutputs = inferRouterOutputs<AppRouter>;
@@ -1,51 +1,156 @@
1
1
  import { z } from 'zod';
2
2
  import { router, publicProcedure, authedProcedure } from '../trpc';
3
+ import { bucket } from 'src/lib/storage';
3
4
 
4
5
  export const workspace = router({
5
6
  // Mutation with Zod input
6
7
  list: publicProcedure
7
8
  .query(async ({ ctx, input }) => {
9
+ const workspaces = await ctx.db.workspace.findMany({
10
+ where: {
11
+ ownerId: ctx.session?.user.id,
12
+ },
13
+ });
14
+ return workspaces;
8
15
  }),
9
16
 
10
17
  create: publicProcedure
11
18
  .input(z.object({
12
-
19
+ name: z.string().min(1).max(100),
20
+ description: z.string().max(500).optional(),
13
21
  }))
14
- .mutation(({ input }) => {
15
-
22
+ .mutation(({ ctx, input}) => {
23
+ return ctx.db.workspace.create({
24
+ data: {
25
+ title: input.name,
26
+ description: input.description,
27
+ ownerId: ctx.session?.user.id,
28
+ },
29
+ });
16
30
  }),
17
31
  get: publicProcedure
18
32
  .input(z.object({
19
33
  id: z.string().uuid(),
20
34
  }))
21
- .query(({ input }) => {
35
+ .query(({ ctx, input }) => {
36
+ return ctx.db.workspace.findUnique({
37
+ where: {
38
+ id: input.id,
39
+ },
40
+ });
22
41
  }),
23
42
  update: publicProcedure
24
43
  .input(z.object({
25
44
  id: z.string().uuid(),
45
+ name: z.string().min(1).max(100).optional(),
46
+ description: z.string().max(500).optional(),
26
47
  }))
27
- .mutation(({ input }) => {
28
-
48
+ .mutation(({ ctx, input }) => {
49
+ return ctx.db.workspace.update({
50
+ where: {
51
+ id: input.id,
52
+ },
53
+ data: {
54
+ title: input.name,
55
+ description: input.description,
56
+ },
57
+ });
29
58
  }),
30
59
  delete: publicProcedure
31
60
  .input(z.object({
32
61
  id: z.string().uuid(),
33
62
  }))
34
- .mutation(({ input }) => {
35
-
63
+ .mutation(({ ctx, input }) => {
64
+ ctx.db.workspace.delete({
65
+ where: {
66
+ id: input.id,
67
+ },
68
+ });
69
+ return true;
36
70
  }),
37
- upload: publicProcedure
71
+ uploadFiles: publicProcedure
38
72
  .input(z.object({
39
- file: z.string(),
73
+ id: z.string().uuid(),
74
+ files: z.array(
75
+ z.object({
76
+ filename: z.string().min(1).max(255),
77
+ contentType: z.string().min(1).max(100),
78
+ size: z.number().min(1), // size in bytes
79
+ })
80
+ ),
40
81
  }))
41
- .mutation(({ input }) => {
42
-
82
+ .mutation(async ({ ctx, input }) => {
83
+ const results = [];
84
+
85
+ for (const file of input.files) {
86
+ // 1. Insert into DB
87
+ const record = await ctx.db.fileAsset.create({
88
+ data: {
89
+ userId: ctx.session.user.id,
90
+ name: file.filename,
91
+ mimeType: file.contentType,
92
+ size: file.size,
93
+ workspaceId: input.id,
94
+ },
95
+ });
96
+
97
+ // 2. Generate signed URL for direct upload
98
+ const [url] = await bucket
99
+ .file(`${ctx.session.user.id}/${record.id}-${file.filename}`)
100
+ .getSignedUrl({
101
+ action: "write",
102
+ expires: Date.now() + 5 * 60 * 1000, // 5 min
103
+ contentType: file.contentType,
104
+ });
105
+
106
+ // 3. Update record with bucket info
107
+ await ctx.db.fileAsset.update({
108
+ where: { id: record.id },
109
+ data: {
110
+ bucket: bucket.name,
111
+ objectKey: `${ctx.session.user.id}/${record.id}-${file.filename}`,
112
+ },
113
+ });
114
+
115
+ results.push({
116
+ fileId: record.id,
117
+ uploadUrl: url,
118
+ });
119
+ }
120
+
121
+ return results;
122
+
43
123
  }),
44
- deleteFile: publicProcedure
124
+ deleteFiles: publicProcedure
45
125
  .input(z.object({
46
- fileId: z.string().uuid(),
126
+ fileId: z.array(z.string().uuid()),
127
+ id: z.string().uuid(),
47
128
  }))
48
- .mutation(({ input }) => {
49
-
129
+ .mutation(({ ctx, input }) => {
130
+ const files = ctx.db.fileAsset.findMany({
131
+ where: {
132
+ id: { in: input.fileId },
133
+ workspaceId: input.id,
134
+ },
135
+ });
136
+
137
+ // Delete from GCS
138
+ files.then((fileRecords) => {
139
+ fileRecords.forEach((file) => {
140
+ if (file.bucket && file.objectKey) {
141
+ const gcsFile = bucket.file(file.objectKey);
142
+ gcsFile.delete({ ignoreNotFound: true }).catch((err: unknown) => {
143
+ console.error(`Error deleting file ${file.objectKey} from bucket ${file.bucket}:`, err);
144
+ });
145
+ }
146
+ });
147
+ });
148
+
149
+ return ctx.db.fileAsset.deleteMany({
150
+ where: {
151
+ id: { in: input.fileId },
152
+ workspaceId: input.id,
153
+ },
154
+ });
50
155
  }),
51
156
  });
package/src/server.ts CHANGED
@@ -16,7 +16,11 @@ async function main() {
16
16
 
17
17
  // Middlewares
18
18
  app.use(helmet());
19
- app.use(cors({ origin: true, credentials: true }));
19
+ app.use(cors({
20
+ origin: "http://localhost:3000", // your Next.js dev URL
21
+ credentials: true, // allow cookies
22
+ }));
23
+
20
24
  app.use(morgan('dev'));
21
25
  app.use(compression());
22
26
  app.use(express.json());
package/tsconfig.json CHANGED
@@ -3,11 +3,15 @@
3
3
  "target": "ES2020",
4
4
  "module": "CommonJS",
5
5
  "moduleResolution": "node",
6
- "outDir": "dist",
7
- "rootDir": "src",
8
- "strict": true,
9
6
  "esModuleInterop": true,
10
- "skipLibCheck": true
7
+ "strict": true,
8
+ "skipLibCheck": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "outDir": "dist",
11
+ "baseUrl": ".",
12
+ "declaration": true,
13
+ "declarationMap": true
11
14
  },
12
- "include": ["src"]
13
- }
15
+ "include": ["src/**/*"],
16
+ "exclude": ["node_modules", "dist"]
17
+ }