@schemavaults/trpc-backend-init 0.8.1

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/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # @schemavaults/trpc-backend-init
2
+
3
+ Repository for easily initializing a tRPC server with SchemaVaults Auth access token validation.
4
+
5
+ ## What This Package Does
6
+
7
+ `@schemavaults/trpc-backend-init` is a tRPC server-side router factory for the SchemaVaults ecosystem. It provides an abstract base class that microservices extend to get type-safe tRPC routers with built-in JWT authentication middleware. The "virtual backend" pattern lets client SDKs target a single router interface that routes to the correct microservice (registry server, regional vault filesystem servers).
8
+
9
+ ## Commands
10
+
11
+ - **Build**: `bun run build` (runs `tsc` then `tsc-alias` to resolve `@/*` path aliases, then removes test files from dist)
12
+ - **Test**: `bun run test` (sets `SCHEMAVAULTS_APP_ENVIRONMENT=test NODE_ENV=test`)
13
+ - **Run single test**: `SCHEMAVAULTS_APP_ENVIRONMENT=test NODE_ENV=test bun test src/context/load_auth_context.test.ts`
14
+
15
+ ## Architecture
16
+
17
+ ### Core Components
18
+
19
+ - **`SchemaVaults_tRPC_Backend<R>`** (`src/schemavaults-trpc-backend.ts`) — Abstract class that consuming services extend. Generic over `R extends Base_SchemaVaults_tRPC_Resources` to allow each service to inject its own resources into the tRPC context. Initializes tRPC once via `initTRPC` and exposes `router` and `lazy` builders.
20
+
21
+ - **Context** (`src/context/`) — `createContext()` factory builds the tRPC context per-request. Calls `loadAuthContext()` which extracts the Bearer token, validates the JWT via `RemoteJwtKeyManager` from `@schemavaults/auth-server-sdk`, and populates `user` and `user_organizations` (or null if unauthenticated).
22
+
23
+ - **Procedures** (`src/procedures/`) — `createProcedures()` factory builds three procedure levels using tRPC middleware:
24
+ - `publicProcedure` — no auth required
25
+ - `authorizedProcedure` — requires authenticated user (throws UNAUTHORIZED)
26
+ - `adminProcedure` — requires authenticated admin user (throws FORBIDDEN)
27
+
28
+ ### Key Types (exported from `src/index.ts`)
29
+
30
+ - `SchemaVaults_tRPC_Context<R>` — The context shape including `user`, `user_organizations`, `connected_server_resources`, `jwt_audience`, `environment`, `debug`
31
+ - `SchemaVaults_tRPC_Runtime` — The initialized tRPC instance type
32
+ - `SchemaVaults_tRPC_Procedures` — The procedure set type
33
+
34
+ ### Dependencies
35
+
36
+ - `@trpc/server` (v11) — tRPC framework
37
+ - `@schemavaults/auth-server-sdk` — JWT validation and remote key management
38
+ - `@schemavaults/app-definitions` — Environment types, auth server URIs, app config
39
+
40
+ ## Environment Variables
41
+
42
+ - `SCHEMAVAULTS_APP_ENVIRONMENT` — App environment (development/test/staging/production)
43
+ - `SCHEMAVAULTS_API_SERVER_ID` — JWT audience identifier (required for auth context)
44
+ - `SCHEMAVAULTS_GITHUB_PACKAGE_REGISTRY_TOKEN` — For installing/publishing to GitHub Packages
45
+
46
+ ## Conventions
47
+
48
+ - Path alias `@/*` maps to `./src/*` — resolved at build time by `tsc-alias`
49
+ - Tests use Bun's built-in test runner (`import { describe, expect, test } from "bun:test"`)
50
+ - Test files (`*.test.ts`) live alongside source files and are excluded from dist by the postbuild cleanup
51
+ - Published to GitHub Packages NPM registry (`@schemavaults` scope)
52
+ - CI runs on push to main: build → test → publish via GitHub Actions
@@ -0,0 +1,23 @@
1
+ import { type AuthContext } from "./load_auth_context";
2
+ import { type SchemaVaultsAppEnvironment } from "@schemavaults/app-definitions";
3
+ import { type OrganizationID, type UserData, type OrganizationMembershipRoleType } from "@schemavaults/auth-server-sdk";
4
+ export interface Base_SchemaVaults_tRPC_Resources {
5
+ }
6
+ export interface SchemaVaults_tRPC_Context<R extends Base_SchemaVaults_tRPC_Resources> {
7
+ user: AuthContext["user"] | null;
8
+ isUserInOrganization: (user: UserData, org_id: OrganizationID) => Promise<OrganizationMembershipRoleType | false>;
9
+ connected_server_resources: R;
10
+ jwt_audience: string;
11
+ environment: SchemaVaultsAppEnvironment;
12
+ debug: boolean;
13
+ }
14
+ export interface ICreateContextFnOptions<R extends Base_SchemaVaults_tRPC_Resources> {
15
+ getAuthHeader(): string | null;
16
+ connected_server_resources: R;
17
+ environment?: SchemaVaultsAppEnvironment;
18
+ debug?: boolean;
19
+ }
20
+ export type CreateContextFn<R extends Base_SchemaVaults_tRPC_Resources> = ({ getAuthHeader, connected_server_resources, }: ICreateContextFnOptions<R>) => Promise<SchemaVaults_tRPC_Context<R>>;
21
+ export declare function createContext<R extends Base_SchemaVaults_tRPC_Resources = Base_SchemaVaults_tRPC_Resources>({ getAuthHeader, connected_server_resources, ...opts }: ICreateContextFnOptions<R>): Promise<SchemaVaults_tRPC_Context<R>>;
22
+ declare const _default: typeof createContext;
23
+ export default _default;
@@ -0,0 +1,94 @@
1
+ import { loadAuthContext } from "./load_auth_context";
2
+ import { TRPCError } from "@trpc/server";
3
+ import { getAppEnvironment, getAuthServerUri, schemaVaultsAppEnvironmentSchema, } from "@schemavaults/app-definitions";
4
+ import { getSchemavaultsApiServerId, isUserInOrganization, loadJwksAccessPrivateKey, } from "@schemavaults/auth-server-sdk";
5
+ export async function createContext({ getAuthHeader, connected_server_resources, ...opts }) {
6
+ let environment;
7
+ if (typeof opts.environment === "string") {
8
+ environment = opts.environment;
9
+ }
10
+ else {
11
+ environment = getAppEnvironment();
12
+ }
13
+ if (!schemaVaultsAppEnvironmentSchema.safeParse(environment).success) {
14
+ throw new Error("Invalid app environment!");
15
+ }
16
+ let debug;
17
+ if (typeof opts.debug === "boolean") {
18
+ debug = opts.debug;
19
+ }
20
+ else {
21
+ debug =
22
+ environment === "development" ||
23
+ environment === "test" ||
24
+ environment === "staging";
25
+ }
26
+ if (debug) {
27
+ console.log("[createContext] Creating tRPC context...");
28
+ }
29
+ let authHeader;
30
+ try {
31
+ authHeader = getAuthHeader();
32
+ }
33
+ catch (e) {
34
+ throw new TRPCError({
35
+ code: "INTERNAL_SERVER_ERROR",
36
+ message: "There was an error parsing authentication details from request headers",
37
+ });
38
+ }
39
+ let jwt_audience;
40
+ try {
41
+ jwt_audience = getSchemavaultsApiServerId();
42
+ }
43
+ catch (e) {
44
+ console.error("[createContext] Failed to load API server ID from environment variables: ", e);
45
+ throw new TRPCError({
46
+ code: "INTERNAL_SERVER_ERROR",
47
+ message: "Internal server error",
48
+ });
49
+ }
50
+ let jwks_access_private_key;
51
+ try {
52
+ jwks_access_private_key = await loadJwksAccessPrivateKey(process.env);
53
+ }
54
+ catch (e) {
55
+ console.error("[createContext] Failed to load JWKS access private key from environment variables: ", e);
56
+ throw new TRPCError({
57
+ code: "INTERNAL_SERVER_ERROR",
58
+ message: "Internal server error",
59
+ });
60
+ }
61
+ try {
62
+ if (debug) {
63
+ console.log("[createContext] Attempting to load auth context...");
64
+ }
65
+ const authContextPromise = loadAuthContext(authHeader);
66
+ if (debug) {
67
+ console.log("[createContext] Attempting to load DB context...");
68
+ }
69
+ const authContext = await authContextPromise;
70
+ if (debug) {
71
+ console.log("[createContext] Loaded auth context: ", authContext);
72
+ }
73
+ const finalContext = {
74
+ user: authContext.user,
75
+ isUserInOrganization: async (user, org_id) => {
76
+ return await isUserInOrganization(getAuthServerUri(environment), jwt_audience, jwks_access_private_key, user["uid"], org_id);
77
+ },
78
+ connected_server_resources,
79
+ jwt_audience,
80
+ environment,
81
+ debug,
82
+ };
83
+ return finalContext;
84
+ }
85
+ catch (error) {
86
+ console.error("[createContext] Error creating tRPC context", error);
87
+ throw new TRPCError({
88
+ code: "INTERNAL_SERVER_ERROR",
89
+ message: "Failed to create tRPC context",
90
+ });
91
+ }
92
+ }
93
+ export default createContext;
94
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/context/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { createContext } from "./context";
2
+ export type { SchemaVaults_tRPC_Context, ICreateContextFnOptions, CreateContextFn, Base_SchemaVaults_tRPC_Resources, } from "./context";
@@ -0,0 +1,2 @@
1
+ export { createContext } from "./context";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/context/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { decodeJWTsWithKeyManager } from "@schemavaults/auth-server-sdk";
2
+ export type AuthContext = Awaited<ReturnType<typeof decodeJWTsWithKeyManager>>;
3
+ import { type SchemaVaultsAppEnvironment } from "@schemavaults/app-definitions";
4
+ export declare function loadAuthContext(authHeader: string | null, environment?: SchemaVaultsAppEnvironment): Promise<AuthContext>;
5
+ export default loadAuthContext;
@@ -0,0 +1,60 @@
1
+ // load_auth_context.ts
2
+ import { getSchemavaultsApiServerId, RemoteJwtKeyManager, decodeJWTsWithKeyManager, } from "@schemavaults/auth-server-sdk";
3
+ import { getAppEnvironment, getAuthServerUri, } from "@schemavaults/app-definitions";
4
+ const bearerPrefix = "Bearer ";
5
+ export async function loadAuthContext(authHeader, environment = getAppEnvironment()) {
6
+ if (!authHeader) {
7
+ if (environment === "development") {
8
+ console.log("[loadAuthContext] No authorization header found");
9
+ }
10
+ return {
11
+ user: null,
12
+ };
13
+ }
14
+ const token = authHeader.startsWith(bearerPrefix)
15
+ ? authHeader.slice(bearerPrefix.length)
16
+ : authHeader;
17
+ // token parsed from header now
18
+ if (!token) {
19
+ if (environment === "development") {
20
+ console.log("[loadAuthContext] No auth token found");
21
+ }
22
+ return {
23
+ user: null,
24
+ };
25
+ }
26
+ const audience = getSchemavaultsApiServerId();
27
+ if (typeof audience !== "string")
28
+ throw new Error("Environment variable 'SCHEMAVAULTS_API_SERVER_ID' not set or passed to auth context loader");
29
+ const remote_jwt_key_manager = new RemoteJwtKeyManager({
30
+ auth_server_uri: getAuthServerUri(),
31
+ debug: environment === "development",
32
+ });
33
+ // Proceed to validate the token
34
+ try {
35
+ if (environment === "development") {
36
+ console.log(`[loadAuthContext] Attempting to verify auth token '${token}'...`);
37
+ }
38
+ const result = await decodeJWTsWithKeyManager(remote_jwt_key_manager, [
39
+ {
40
+ token,
41
+ sourceHint: "tRPC Authorization Bearer Header",
42
+ type: "access",
43
+ },
44
+ ]);
45
+ if (environment === "development" && result.user) {
46
+ console.log(`[loadAuthContext] Successfully verified auth token for user '${result.user.email}'`);
47
+ }
48
+ return result;
49
+ }
50
+ catch (error) {
51
+ if (environment === "development") {
52
+ console.warn("[loadAuthContext] Could not verify the token: ", error);
53
+ }
54
+ return {
55
+ user: null,
56
+ };
57
+ }
58
+ }
59
+ export default loadAuthContext;
60
+ //# sourceMappingURL=load_auth_context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load_auth_context.js","sourceRoot":"","sources":["../../src/context/load_auth_context.ts"],"names":[],"mappings":"AAAA,uBAAuB;AAEvB,OAAO,EACL,0BAA0B,EAC1B,mBAAmB,EACnB,wBAAwB,GAEzB,MAAM,+BAA+B,CAAC;AAIvC,OAAO,EAEL,iBAAiB,EACjB,gBAAgB,GAEjB,MAAM,+BAA+B,CAAC;AAEvC,MAAM,YAAY,GAAc,SAAkB,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAAyB,EACzB,cAA0C,iBAAiB,EAAE;IAE7D,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,IAAI,WAAW,KAAK,aAAa,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;QACjE,CAAC;QACD,OAAO;YACL,IAAI,EAAE,IAAI;SACX,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAuB,UAAU,CAAC,UAAU,CAAC,YAAY,CAAC;QACnE,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC;QACvC,CAAC,CAAC,UAAU,CAAC;IACf,+BAA+B;IAE/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,IAAI,WAAW,KAAK,aAAa,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;QACvD,CAAC;QACD,OAAO;YACL,IAAI,EAAE,IAAI;SACX,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAgB,0BAA0B,EAAE,CAAC;IAC3D,IAAI,OAAO,QAAQ,KAAK,QAAQ;QAC9B,MAAM,IAAI,KAAK,CACb,4FAA4F,CAC7F,CAAC;IAEJ,MAAM,sBAAsB,GAAmB,IAAI,mBAAmB,CAAC;QACrE,eAAe,EAAE,gBAAgB,EAAE;QACnC,KAAK,EAAE,WAAW,KAAK,aAAa;KACrC,CAAC,CAAC;IAEH,gCAAgC;IAChC,IAAI,CAAC;QACH,IAAI,WAAW,KAAK,aAAa,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CACT,sDAAsD,KAAK,MAAM,CAClE,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,wBAAwB,CAAC,sBAAsB,EAAE;YACpE;gBACE,KAAK;gBACL,UAAU,EAAE,kCAAkC;gBAC9C,IAAI,EAAE,QAAQ;aACf;SACF,CAAC,CAAC;QAEH,IAAI,WAAW,KAAK,aAAa,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YACjD,OAAO,CAAC,GAAG,CACT,gEAAgE,MAAM,CAAC,IAAI,CAAC,KAAK,GAAG,CACrF,CAAC;QACJ,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,IAAI,WAAW,KAAK,aAAa,EAAE,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,gDAAgD,EAAE,KAAK,CAAC,CAAC;QACxE,CAAC;QACD,OAAO;YACL,IAAI,EAAE,IAAI;SACX,CAAC;IACJ,CAAC;AACH,CAAC;AAED,eAAe,eAAe,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { SchemaVaultsAppEnvironment } from "@schemavaults/app-definitions";
2
+ declare global {
3
+ namespace NodeJS {
4
+ interface ProcessEnv {
5
+ NODE_ENV: SchemaVaultsAppEnvironment;
6
+ }
7
+ }
8
+ }
9
+ export { SchemaVaults_tRPC_Backend } from "./schemavaults-trpc-backend";
10
+ export type { SchemaVaults_tRPC_Context, ICreateContextFnOptions, CreateContextFn, Base_SchemaVaults_tRPC_Resources, } from "./context";
11
+ export type { SchemaVaults_tRPC_Runtime } from "./schemavaults-trpc-runtime";
12
+ export type { SchemaVaults_tRPC_Procedures } from "./procedures";
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { SchemaVaults_tRPC_Backend } from "./schemavaults-trpc-backend";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC"}
@@ -0,0 +1,44 @@
1
+ import type { Base_SchemaVaults_tRPC_Resources } from "../context";
2
+ import type { SchemaVaults_tRPC_Runtime } from "../schemavaults-trpc-runtime";
3
+ import type { UserData } from "@schemavaults/auth-server-sdk";
4
+ export declare function createProcedures<R extends Base_SchemaVaults_tRPC_Resources>(middleware: SchemaVaults_tRPC_Runtime<R>["middleware"], procedure: SchemaVaults_tRPC_Runtime<R>["procedure"]): {
5
+ readonly public: import("@trpc/server").TRPCProcedureBuilder<import("../context").SchemaVaults_tRPC_Context<R>, object, object, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, false>;
6
+ readonly authorized: import("@trpc/server").TRPCProcedureBuilder<import("../context").SchemaVaults_tRPC_Context<R>, object, {
7
+ user: {
8
+ uid: string;
9
+ sub: string;
10
+ email: string;
11
+ created_at: number;
12
+ email_verified?: boolean | undefined;
13
+ admin?: boolean | undefined;
14
+ phone_number?: string | undefined;
15
+ phone_verified?: boolean | undefined;
16
+ disabled?: boolean | undefined;
17
+ invite_code?: string | undefined;
18
+ };
19
+ connected_server_resources: R;
20
+ environment: "development" | "staging" | "test" | "production";
21
+ debug: boolean;
22
+ isUserInOrganization: (user: UserData, org_id: import("@schemavaults/auth-common").OrganizationID) => Promise<import("@schemavaults/auth-common").OrganizationMembershipRoleType | false>;
23
+ jwt_audience: string;
24
+ }, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, false>;
25
+ readonly admin: import("@trpc/server").TRPCProcedureBuilder<import("../context").SchemaVaults_tRPC_Context<R>, object, {
26
+ user: {
27
+ uid: string;
28
+ sub: string;
29
+ email: string;
30
+ created_at: number;
31
+ email_verified?: boolean | undefined;
32
+ admin?: boolean | undefined;
33
+ phone_number?: string | undefined;
34
+ phone_verified?: boolean | undefined;
35
+ disabled?: boolean | undefined;
36
+ invite_code?: string | undefined;
37
+ } | null;
38
+ connected_server_resources: R;
39
+ environment: "development" | "staging" | "test" | "production";
40
+ debug: boolean;
41
+ isUserInOrganization: (user: UserData, org_id: import("@schemavaults/auth-common").OrganizationID) => Promise<import("@schemavaults/auth-common").OrganizationMembershipRoleType | false>;
42
+ jwt_audience: string;
43
+ }, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, false>;
44
+ };
@@ -0,0 +1,44 @@
1
+ import { TRPCError } from "@trpc/server";
2
+ export function createProcedures(middleware, procedure) {
3
+ // "Base Procedure" -- most procedures should be behind authentication middleware (instead of importing here)
4
+ const publicProcedure = procedure;
5
+ const isAuthed = middleware((opts) => {
6
+ const { ctx } = opts;
7
+ if (!ctx) {
8
+ throw new TRPCError({
9
+ code: "INTERNAL_SERVER_ERROR",
10
+ message: "No context found",
11
+ });
12
+ }
13
+ if (!ctx.user) {
14
+ throw new TRPCError({
15
+ code: "UNAUTHORIZED",
16
+ message: "You must be logged in to perform this action",
17
+ });
18
+ }
19
+ const user = ctx.user;
20
+ return opts.next({
21
+ ctx: {
22
+ ...ctx,
23
+ user,
24
+ },
25
+ });
26
+ });
27
+ const authorizedProcedure = publicProcedure.use(isAuthed);
28
+ const isAdmin = middleware((opts) => {
29
+ if (!opts.ctx.user?.admin) {
30
+ throw new TRPCError({
31
+ code: "FORBIDDEN",
32
+ message: "You must be an admin user to perform this action",
33
+ });
34
+ }
35
+ return opts.next(opts);
36
+ });
37
+ const adminProcedure = authorizedProcedure.use(isAdmin);
38
+ return {
39
+ public: publicProcedure,
40
+ authorized: authorizedProcedure,
41
+ admin: adminProcedure,
42
+ };
43
+ }
44
+ //# sourceMappingURL=create_procedures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create_procedures.js","sourceRoot":"","sources":["../../src/procedures/create_procedures.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,gBAAgB,CAC9B,UAAsD,EACtD,SAAoD;IAEpD,6GAA6G;IAC7G,MAAM,eAAe,GAA8C,SAAS,CAAC;IAE7E,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE;QACnC,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,SAAS,CAAC;gBAClB,IAAI,EAAE,uBAAuB;gBAC7B,OAAO,EAAE,kBAAkB;aAC5B,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACd,MAAM,IAAI,SAAS,CAAC;gBAClB,IAAI,EAAE,cAAc;gBACpB,OAAO,EAAE,8CAA8C;aACxD,CAAC,CAAC;QACL,CAAC;QAED,MAAM,IAAI,GAAa,GAAG,CAAC,IAAI,CAAC;QAEhC,OAAO,IAAI,CAAC,IAAI,CAAC;YACf,GAAG,EAAE;gBACH,GAAG,GAAG;gBACN,IAAI;aACL;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,mBAAmB,GAAG,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAE1D,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE;QAClC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;YAC1B,MAAM,IAAI,SAAS,CAAC;gBAClB,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,kDAAkD;aAC5D,CAAC,CAAC;QACL,CAAC;QAED,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,MAAM,cAAc,GAAG,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAExD,OAAO;QACL,MAAM,EAAE,eAAe;QACvB,UAAU,EAAE,mBAAmB;QAC/B,KAAK,EAAE,cAAc;KACb,CAAC;AACb,CAAC"}
@@ -0,0 +1,2 @@
1
+ export type { SchemaVaults_tRPC_Procedures } from "./schemavaults-trpc-procedures";
2
+ export { createProcedures } from "./create_procedures";
@@ -0,0 +1,2 @@
1
+ export { createProcedures } from "./create_procedures";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/procedures/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Base_SchemaVaults_tRPC_Resources } from "../context";
2
+ import type { createProcedures } from "./create_procedures";
3
+ export type SchemaVaults_tRPC_Procedures<R extends Base_SchemaVaults_tRPC_Resources> = ReturnType<typeof createProcedures<R>>;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=schemavaults-trpc-procedures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemavaults-trpc-procedures.js","sourceRoot":"","sources":["../../src/procedures/schemavaults-trpc-procedures.ts"],"names":[],"mappings":""}
@@ -0,0 +1,22 @@
1
+ import { lazy } from "@trpc/server";
2
+ import { type ICreateContextFnOptions, type Base_SchemaVaults_tRPC_Resources, type SchemaVaults_tRPC_Context } from "./context";
3
+ import type { SchemaVaults_tRPC_Runtime } from "./schemavaults-trpc-runtime";
4
+ import { createProcedures, type SchemaVaults_tRPC_Procedures } from "./procedures";
5
+ export declare abstract class SchemaVaults_tRPC_Backend<R extends Base_SchemaVaults_tRPC_Resources> {
6
+ protected _trpc: SchemaVaults_tRPC_Runtime<R>;
7
+ protected _trpc_procedures: ReturnType<typeof createProcedures<R>>;
8
+ constructor();
9
+ abstract get trpc(): SchemaVaults_tRPC_Runtime<R>;
10
+ abstract get procedures(): SchemaVaults_tRPC_Procedures<R>;
11
+ get router(): SchemaVaults_tRPC_Runtime<R>["router"];
12
+ /**
13
+ * @name lazy
14
+ * @description Lazy load a tRPC backend router
15
+ */
16
+ get lazy(): typeof lazy;
17
+ /**
18
+ * @name createContext
19
+ * @description Initialize tRPC context accessible to procedures
20
+ */
21
+ createContext(opts: ICreateContextFnOptions<R>): Promise<SchemaVaults_tRPC_Context<R>>;
22
+ }
@@ -0,0 +1,31 @@
1
+ // schemavaults-trpc-backend.ts
2
+ import { initTRPC, lazy } from "@trpc/server";
3
+ import { createContext, } from "./context";
4
+ import { createProcedures, } from "./procedures";
5
+ export class SchemaVaults_tRPC_Backend {
6
+ _trpc;
7
+ _trpc_procedures;
8
+ constructor() {
9
+ // tRPC should only be initialized ONCE per server, so we initialize it here.
10
+ this._trpc = initTRPC.context().create();
11
+ this._trpc_procedures = createProcedures(this._trpc.middleware, this._trpc.procedure);
12
+ }
13
+ get router() {
14
+ return this.trpc.router;
15
+ }
16
+ /**
17
+ * @name lazy
18
+ * @description Lazy load a tRPC backend router
19
+ */
20
+ get lazy() {
21
+ return lazy;
22
+ }
23
+ /**
24
+ * @name createContext
25
+ * @description Initialize tRPC context accessible to procedures
26
+ */
27
+ async createContext(opts) {
28
+ return await createContext(opts);
29
+ }
30
+ }
31
+ //# sourceMappingURL=schemavaults-trpc-backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemavaults-trpc-backend.js","sourceRoot":"","sources":["../src/schemavaults-trpc-backend.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAE/B,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EACL,aAAa,GAId,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,gBAAgB,GAEjB,MAAM,cAAc,CAAC;AAEtB,MAAM,OAAgB,yBAAyB;IAGnC,KAAK,CAA+B;IACpC,gBAAgB,CAAyC;IAEnE;QACE,6EAA6E;QAC7E,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC,OAAO,EAAgC,CAAC,MAAM,EAAE,CAAC;QACvE,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CACtC,IAAI,CAAC,KAAK,CAAC,UAAU,EACrB,IAAI,CAAC,KAAK,CAAC,SAAS,CACrB,CAAC;IACJ,CAAC;IAMD,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACH,IAAW,IAAI;QACb,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,aAAa,CACxB,IAAgC;QAEhC,OAAO,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ import type { initTRPC } from "@trpc/server";
2
+ import type { Base_SchemaVaults_tRPC_Resources, SchemaVaults_tRPC_Context } from "./context";
3
+ type BuilderContext<R extends Base_SchemaVaults_tRPC_Resources> = ReturnType<typeof initTRPC.context<SchemaVaults_tRPC_Context<R>>>;
4
+ export type SchemaVaults_tRPC_Runtime<R extends Base_SchemaVaults_tRPC_Resources> = ReturnType<BuilderContext<R>["create"]>;
5
+ export {};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=schemavaults-trpc-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemavaults-trpc-runtime.js","sourceRoot":"","sources":["../src/schemavaults-trpc-runtime.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@schemavaults/trpc-backend-init",
3
+ "description": "tRPC Server-side Router Factory",
4
+ "version": "0.8.1",
5
+ "private": false,
6
+ "license": "UNLICENSED",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/schemavaults/trpc-backend-init.git"
10
+ },
11
+ "dependencies": {},
12
+ "devDependencies": {
13
+ "typescript": "5.9.3",
14
+ "bun-types": "1.3.11",
15
+ "tsc-alias": "1.8.16"
16
+ },
17
+ "peerDependencies": {
18
+ "@trpc/server": "11.16.0",
19
+ "@schemavaults/auth-server-sdk": "0.22.18",
20
+ "@schemavaults/app-definitions": "0.6.23"
21
+ },
22
+ "scripts": {
23
+ "build": "tsc --project ./tsconfig.json && tsc-alias --project ./tsconfig.json",
24
+ "postbuild": "bun run cleanup",
25
+ "cleanup:compiled_tests_in_dist_directory": "find ./dist -type f \\( -name \"*.test.js\" -o -name \"*.test.js.map\" -o -name \"*.test.d.ts\" \\) -delete",
26
+ "cleanup": "bun run cleanup:compiled_tests_in_dist_directory",
27
+ "test": "SCHEMAVAULTS_APP_ENVIRONMENT=test NODE_ENV=test bun test"
28
+ },
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "main": "dist/index.js",
33
+ "types": "dist/index.d.ts",
34
+ "module": "dist/index.js",
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "packageManager": "bun@1.3.11"
39
+ }