@m5kdev/backend 0.5.0 → 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.
@@ -3260,13 +3260,13 @@ export declare function createBetterAuth<O extends Orm, S extends Schema, E exte
3260
3260
  $Infer: {
3261
3261
  body: ({
3262
3262
  permission: {
3263
- readonly user?: ("get" | "update" | "set-role" | "create" | "delete" | "list" | "ban" | "impersonate" | "set-password")[] | undefined;
3263
+ readonly user?: ("get" | "set-role" | "create" | "update" | "delete" | "list" | "ban" | "impersonate" | "set-password")[] | undefined;
3264
3264
  readonly session?: ("delete" | "list" | "revoke")[] | undefined;
3265
3265
  };
3266
3266
  permissions?: never | undefined;
3267
3267
  } | {
3268
3268
  permissions: {
3269
- readonly user?: ("get" | "update" | "set-role" | "create" | "delete" | "list" | "ban" | "impersonate" | "set-password")[] | undefined;
3269
+ readonly user?: ("get" | "set-role" | "create" | "update" | "delete" | "list" | "ban" | "impersonate" | "set-password")[] | undefined;
3270
3270
  readonly session?: ("delete" | "list" | "revoke")[] | undefined;
3271
3271
  };
3272
3272
  permission?: never | undefined;
@@ -3528,7 +3528,7 @@ export declare function createBetterAuth<O extends Orm, S extends Schema, E exte
3528
3528
  id: string;
3529
3529
  organizationId: string;
3530
3530
  email: string;
3531
- role: "member" | "owner" | "admin";
3531
+ role: "admin" | "member" | "owner";
3532
3532
  status: import("better-auth/plugins", { with: { "resolution-mode": "import" } }).InvitationStatus;
3533
3533
  inviterId: string;
3534
3534
  expiresAt: Date;
@@ -3538,7 +3538,7 @@ export declare function createBetterAuth<O extends Orm, S extends Schema, E exte
3538
3538
  Member: {
3539
3539
  id: string;
3540
3540
  organizationId: string;
3541
- role: "member" | "owner" | "admin";
3541
+ role: "admin" | "member" | "owner";
3542
3542
  createdAt: Date;
3543
3543
  userId: string;
3544
3544
  teamId?: string | undefined | undefined;
@@ -3566,7 +3566,7 @@ export declare function createBetterAuth<O extends Orm, S extends Schema, E exte
3566
3566
  members: {
3567
3567
  id: string;
3568
3568
  organizationId: string;
3569
- role: "member" | "owner" | "admin";
3569
+ role: "admin" | "member" | "owner";
3570
3570
  createdAt: Date;
3571
3571
  userId: string;
3572
3572
  teamId?: string | undefined | undefined;
@@ -3581,7 +3581,7 @@ export declare function createBetterAuth<O extends Orm, S extends Schema, E exte
3581
3581
  id: string;
3582
3582
  organizationId: string;
3583
3583
  email: string;
3584
- role: "member" | "owner" | "admin";
3584
+ role: "admin" | "member" | "owner";
3585
3585
  status: import("better-auth/plugins", { with: { "resolution-mode": "import" } }).InvitationStatus;
3586
3586
  inviterId: string;
3587
3587
  expiresAt: Date;
@@ -4811,7 +4811,7 @@ export declare function createBetterAuth<O extends Orm, S extends Schema, E exte
4811
4811
  } | undefined;
4812
4812
  verification?: {
4813
4813
  modelName?: string;
4814
- fields?: Partial<Record<"value" | "createdAt" | "updatedAt" | "expiresAt" | "identifier", string>>;
4814
+ fields?: Partial<Record<"createdAt" | "updatedAt" | "expiresAt" | "value" | "identifier", string>>;
4815
4815
  additionalFields?: {
4816
4816
  [key: string]: import("better-auth", { with: { "resolution-mode": "import" } }).DBFieldAttribute;
4817
4817
  };
@@ -49,10 +49,10 @@ export declare function createAuthTRPC({ router, publicProcedure, privateProcedu
49
49
  input: void;
50
50
  output: {
51
51
  id: string;
52
- status: string;
53
52
  createdAt: Date;
54
53
  updatedAt: Date | null;
55
54
  expiresAt: Date | null;
55
+ status: string;
56
56
  claimUserId: string | null;
57
57
  claimedAt: Date | null;
58
58
  claimedEmail: string | null;
@@ -67,11 +67,11 @@ export declare function createAuthTRPC({ router, publicProcedure, privateProcedu
67
67
  output: {
68
68
  id: string;
69
69
  email: string;
70
- url: string;
71
70
  createdAt: Date;
72
- userId: string;
73
71
  expiresAt: Date | null;
72
+ userId: string;
74
73
  claimId: string;
74
+ url: string;
75
75
  };
76
76
  meta: any;
77
77
  }>;
@@ -82,11 +82,11 @@ export declare function createAuthTRPC({ router, publicProcedure, privateProcedu
82
82
  output: {
83
83
  id: string;
84
84
  email: string;
85
- url: string;
86
85
  createdAt: Date;
87
- userId: string;
88
86
  expiresAt: Date | null;
87
+ userId: string;
89
88
  claimId: string;
89
+ url: string;
90
90
  }[];
91
91
  meta: any;
92
92
  }>;
@@ -139,11 +139,11 @@ export declare function createAuthTRPC({ router, publicProcedure, privateProcedu
139
139
  input: void;
140
140
  output: {
141
141
  id: string;
142
- email: string | null;
143
142
  name: string | null;
144
- status: string;
143
+ email: string | null;
145
144
  createdAt: Date;
146
145
  updatedAt: Date | null;
146
+ status: string;
147
147
  }[];
148
148
  meta: any;
149
149
  }>;
@@ -153,11 +153,11 @@ export declare function createAuthTRPC({ router, publicProcedure, privateProcedu
153
153
  };
154
154
  output: {
155
155
  id: string;
156
- email: string | null;
157
156
  name: string | null;
158
- status: string;
157
+ email: string | null;
159
158
  createdAt: Date;
160
159
  updatedAt: Date | null;
160
+ status: string;
161
161
  };
162
162
  meta: any;
163
163
  }>;
@@ -184,11 +184,11 @@ export declare function createAuthTRPC({ router, publicProcedure, privateProcedu
184
184
  };
185
185
  output: {
186
186
  id: string;
187
- email: string | null;
188
187
  name: string | null;
189
- status: string;
188
+ email: string | null;
190
189
  createdAt: Date;
191
190
  updatedAt: Date | null;
191
+ status: string;
192
192
  };
193
193
  meta: any;
194
194
  }>;
@@ -198,11 +198,11 @@ export declare function createAuthTRPC({ router, publicProcedure, privateProcedu
198
198
  };
199
199
  output: {
200
200
  id: string;
201
- email: string | null;
202
201
  name: string | null;
203
- status: string;
202
+ email: string | null;
204
203
  createdAt: Date;
205
204
  updatedAt: Date | null;
205
+ status: string;
206
206
  };
207
207
  meta: any;
208
208
  }>;
@@ -212,11 +212,11 @@ export declare function createAuthTRPC({ router, publicProcedure, privateProcedu
212
212
  };
213
213
  output: {
214
214
  id: string;
215
- email: string | null;
216
215
  name: string | null;
217
- status: string;
216
+ email: string | null;
218
217
  createdAt: Date;
219
218
  updatedAt: Date | null;
219
+ status: string;
220
220
  };
221
221
  meta: any;
222
222
  }>;
@@ -1,8 +1,8 @@
1
1
  import type { TRPC_ERROR_CODE_KEY } from "@trpc/server";
2
- import type { ServerResult, ServerResultAsync } from "./base.dto";
3
- import type { ServerErrorLayer } from "./base.types";
4
2
  import { ServerError } from "../../utils/errors";
5
3
  import { logger } from "../../utils/logger";
4
+ import type { ServerResult, ServerResultAsync } from "./base.dto";
5
+ import type { ServerErrorLayer } from "./base.types";
6
6
  export declare abstract class Base {
7
7
  layer: ServerErrorLayer;
8
8
  logger: ReturnType<typeof logger.child>;
@@ -15,4 +15,5 @@ export declare abstract class Base {
15
15
  handleUnknownError(error: unknown): ServerError;
16
16
  throwable<T>(fn: () => ServerResult<T>): ServerResult<T>;
17
17
  throwableAsync<T>(fn: () => ServerResultAsync<T>): ServerResultAsync<T>;
18
+ throwablePromise<T>(fn: () => Promise<T>, errorHandler?: (error: unknown) => ServerError): ServerResultAsync<T>;
18
19
  }
@@ -43,11 +43,20 @@ class Base {
43
43
  }
44
44
  async throwableAsync(fn) {
45
45
  try {
46
- return fn();
46
+ return await fn();
47
47
  }
48
48
  catch (error) {
49
49
  return (0, neverthrow_1.err)(this.handleUnknownError(error));
50
50
  }
51
51
  }
52
+ async throwablePromise(fn, errorHandler) {
53
+ try {
54
+ const result = await fn();
55
+ return (0, neverthrow_1.ok)(result);
56
+ }
57
+ catch (error) {
58
+ return (0, neverthrow_1.err)(errorHandler ? errorHandler(error) : this.handleUnknownError(error));
59
+ }
60
+ }
52
61
  }
53
62
  exports.Base = Base;
@@ -0,0 +1,112 @@
1
+ import type { QueryInput } from "@m5kdev/commons/modules/schemas/query.schema";
2
+ import type { TRPC_ERROR_CODE_KEY } from "@trpc/server";
3
+ import type { ServerError } from "../../utils/errors";
4
+ import type { logger } from "../../utils/logger";
5
+ import type { Context, Session, User } from "../auth/auth.lib";
6
+ import type { Base } from "./base.abstract";
7
+ import type { ServerResult, ServerResultAsync } from "./base.dto";
8
+ import type { Entity, ResourceActionGrant } from "./base.grants";
9
+ type ServiceLogger = ReturnType<typeof logger.child>;
10
+ type RepositoryMap = Record<string, Base>;
11
+ type ServiceMap = Record<string, Base>;
12
+ export type ServiceProcedureContext = {
13
+ user?: User | null;
14
+ session?: Session | null;
15
+ } & Record<string, unknown>;
16
+ export type ServiceProcedureState = Record<string, unknown>;
17
+ export type ServiceProcedureStoredValue<T> = [T] extends [undefined] ? undefined : Awaited<T>;
18
+ export type ServiceProcedureResultLike<T> = T | ServerResult<T> | Promise<T | ServerResult<T>>;
19
+ export type ServiceProcedureContextFilterScope = "user" | "organization" | "team";
20
+ export type ServiceProcedureContextFilteredInput<TInput> = Extract<NonNullable<TInput>, QueryInput>;
21
+ export type ServiceProcedure<TInput, TCtx extends ServiceProcedureContext, TOutput> = (input: TInput, ctx: TCtx) => ServerResultAsync<TOutput>;
22
+ export type ServiceProcedureArgs<TInput, TCtx extends ServiceProcedureContext, Repositories extends RepositoryMap, Services extends ServiceMap, State extends ServiceProcedureState> = {
23
+ input: TInput;
24
+ ctx: TCtx;
25
+ state: State;
26
+ repository: Repositories;
27
+ service: Services;
28
+ logger: ServiceLogger;
29
+ };
30
+ export type ServiceProcedureStep<TInput, TCtx extends ServiceProcedureContext, Repositories extends RepositoryMap, Services extends ServiceMap, State extends ServiceProcedureState, TOutput = undefined> = (args: ServiceProcedureArgs<TInput, TCtx, Repositories, Services, State>) => ServiceProcedureResultLike<ServiceProcedureStoredValue<TOutput>>;
31
+ export type ServiceProcedureInputMapper<TInput, TCtx extends ServiceProcedureContext, Repositories extends RepositoryMap, Services extends ServiceMap, State extends ServiceProcedureState, TNextInput> = (args: ServiceProcedureArgs<TInput, TCtx, Repositories, Services, State>) => ServiceProcedureResultLike<ServiceProcedureStoredValue<TNextInput>>;
32
+ export type ServiceProcedureHandler<TInput, TCtx extends ServiceProcedureContext, Repositories extends RepositoryMap, Services extends ServiceMap, State extends ServiceProcedureState, TOutput> = (args: ServiceProcedureArgs<TInput, TCtx, Repositories, Services, State>) => ServiceProcedureResultLike<TOutput>;
33
+ export type ServiceProcedureEntityResolver<TInput, TCtx extends ServiceProcedureContext, Repositories extends RepositoryMap, Services extends ServiceMap, State extends ServiceProcedureState, TEntities extends Entity | Entity[] | undefined> = TEntities | ((args: ServiceProcedureArgs<TInput, TCtx, Repositories, Services, State>) => ServiceProcedureResultLike<TEntities>);
34
+ type ServiceProcedureAccessBaseConfig = {
35
+ action: string;
36
+ grants?: ResourceActionGrant[];
37
+ };
38
+ export type ServiceProcedureEntityStepName<State extends ServiceProcedureState> = Extract<{
39
+ [Key in keyof State]: State[Key] extends Entity | Entity[] | undefined ? Key : never;
40
+ }[keyof State], string>;
41
+ export type ServiceProcedureAccessEntitiesConfig<TInput, TCtx extends ServiceProcedureContext, Repositories extends RepositoryMap, Services extends ServiceMap, State extends ServiceProcedureState, TEntities extends Entity | Entity[] | undefined = undefined> = ServiceProcedureAccessBaseConfig & {
42
+ entities?: ServiceProcedureEntityResolver<TInput, TCtx, Repositories, Services, State, TEntities>;
43
+ entityStep?: never;
44
+ };
45
+ export type ServiceProcedureAccessStateConfig<State extends ServiceProcedureState, StepName extends ServiceProcedureEntityStepName<State>> = ServiceProcedureAccessBaseConfig & {
46
+ entityStep: StepName;
47
+ entities?: never;
48
+ };
49
+ export type ServiceProcedureAccessConfig<TInput, TCtx extends ServiceProcedureContext, Repositories extends RepositoryMap, Services extends ServiceMap, State extends ServiceProcedureState, TEntities extends Entity | Entity[] | undefined = undefined> = ServiceProcedureAccessEntitiesConfig<TInput, TCtx, Repositories, Services, State, TEntities> | ServiceProcedureAccessStateConfig<State, ServiceProcedureEntityStepName<State>>;
50
+ export interface ServiceProcedureBuilder<TInput, TCtx extends ServiceProcedureContext, Repositories extends RepositoryMap, Services extends ServiceMap, State extends ServiceProcedureState = Record<string, never>> {
51
+ use<StepName extends string, TOutput = void>(stepName: StepName, step: ServiceProcedureStep<TInput, TCtx, Repositories, Services, State, TOutput>): ServiceProcedureBuilder<TInput, TCtx, Repositories, Services, State & Record<StepName, ServiceProcedureStoredValue<TOutput>>>;
52
+ mapInput<StepName extends string, TNextInput>(stepName: StepName, step: ServiceProcedureInputMapper<TInput, TCtx, Repositories, Services, State, TNextInput>): ServiceProcedureBuilder<ServiceProcedureStoredValue<TNextInput>, TCtx, Repositories, Services, State & Record<StepName, ServiceProcedureStoredValue<TNextInput>>>;
53
+ addContextFilter(include?: readonly ServiceProcedureContextFilterScope[]): ServiceProcedureBuilder<ServiceProcedureContextFilteredInput<TInput>, TCtx & Context, Repositories, Services, State & {
54
+ contextFilter: ServiceProcedureContextFilteredInput<TInput>;
55
+ }>;
56
+ requireAuth(): ServiceProcedureBuilder<TInput, TCtx & Context, Repositories, Services, State>;
57
+ handle<TOutput>(handler: ServiceProcedureHandler<TInput, TCtx, Repositories, Services, State, TOutput>): ServiceProcedure<TInput, TCtx, TOutput>;
58
+ }
59
+ export interface PermissionServiceProcedureBuilder<TInput, TCtx extends ServiceProcedureContext, Repositories extends RepositoryMap, Services extends ServiceMap, State extends ServiceProcedureState = Record<string, never>> extends ServiceProcedureBuilder<TInput, TCtx, Repositories, Services, State> {
60
+ use<StepName extends string, TOutput = void>(stepName: StepName, step: ServiceProcedureStep<TInput, TCtx, Repositories, Services, State, TOutput>): PermissionServiceProcedureBuilder<TInput, TCtx, Repositories, Services, State & Record<StepName, ServiceProcedureStoredValue<TOutput>>>;
61
+ mapInput<StepName extends string, TNextInput>(stepName: StepName, step: ServiceProcedureInputMapper<TInput, TCtx, Repositories, Services, State, TNextInput>): PermissionServiceProcedureBuilder<ServiceProcedureStoredValue<TNextInput>, TCtx, Repositories, Services, State & Record<StepName, ServiceProcedureStoredValue<TNextInput>>>;
62
+ addContextFilter(include?: readonly ServiceProcedureContextFilterScope[]): PermissionServiceProcedureBuilder<ServiceProcedureContextFilteredInput<TInput>, TCtx & Context, Repositories, Services, State & {
63
+ contextFilter: ServiceProcedureContextFilteredInput<TInput>;
64
+ }>;
65
+ requireAuth(): PermissionServiceProcedureBuilder<TInput, TCtx & Context, Repositories, Services, State>;
66
+ access(config: ServiceProcedureAccessEntitiesConfig<TInput, TCtx, Repositories, Services, State>): PermissionServiceProcedureBuilder<TInput, TCtx & Context, Repositories, Services, State>;
67
+ access<TEntities extends Entity | Entity[] | undefined>(config: ServiceProcedureAccessEntitiesConfig<TInput, TCtx, Repositories, Services, State, TEntities>): PermissionServiceProcedureBuilder<TInput, TCtx & Context, Repositories, Services, State & {
68
+ access: TEntities;
69
+ }>;
70
+ access<StepName extends ServiceProcedureEntityStepName<State>>(config: ServiceProcedureAccessStateConfig<State, StepName>): PermissionServiceProcedureBuilder<TInput, TCtx & Context, Repositories, Services, State & {
71
+ access: State[StepName];
72
+ }>;
73
+ }
74
+ type BaseServiceProcedureHost<Repositories extends RepositoryMap, Services extends ServiceMap> = {
75
+ repository: Repositories;
76
+ service: Services;
77
+ logger: ServiceLogger;
78
+ addContextFilter(ctx: Context, include?: {
79
+ user?: boolean;
80
+ organization?: boolean;
81
+ team?: boolean;
82
+ }, query?: QueryInput): QueryInput;
83
+ error(code: TRPC_ERROR_CODE_KEY, message?: string, options?: {
84
+ cause?: unknown;
85
+ clientMessage?: string;
86
+ log?: boolean;
87
+ }): ServerResult<never>;
88
+ throwableAsync<T>(fn: () => ServerResultAsync<T>): ServerResultAsync<T>;
89
+ handleUnknownError(error: unknown): ServerError;
90
+ };
91
+ type PermissionServiceProcedureHost<Repositories extends RepositoryMap, Services extends ServiceMap> = BaseServiceProcedureHost<Repositories, Services> & {
92
+ checkPermission<T extends Entity>(ctx: {
93
+ session: Session;
94
+ user: User;
95
+ }, action: string, entities?: T | T[], grants?: ResourceActionGrant[]): boolean;
96
+ checkPermissionAsync<T extends Entity>(ctx: {
97
+ session: Session;
98
+ user: User;
99
+ }, action: string, getEntities: () => ServerResultAsync<T | T[] | undefined>, grants?: ResourceActionGrant[]): ServerResultAsync<boolean>;
100
+ };
101
+ type ProcedureRuntimeStep<Repositories extends RepositoryMap, Services extends ServiceMap> = {
102
+ stage: "use" | "input" | "auth" | "access";
103
+ stepName: string;
104
+ run: (args: ServiceProcedureArgs<unknown, ServiceProcedureContext, Repositories, Services, ServiceProcedureState>) => Promise<ServerResult<unknown>>;
105
+ };
106
+ type ProcedureBuilderConfig<Repositories extends RepositoryMap, Services extends ServiceMap> = {
107
+ name: string;
108
+ steps: ProcedureRuntimeStep<Repositories, Services>[];
109
+ };
110
+ export declare function createServiceProcedureBuilder<TInput, TCtx extends ServiceProcedureContext, Repositories extends RepositoryMap, Services extends ServiceMap, State extends ServiceProcedureState = Record<string, never>>(host: BaseServiceProcedureHost<Repositories, Services>, config: ProcedureBuilderConfig<Repositories, Services>): ServiceProcedureBuilder<TInput, TCtx, Repositories, Services, State>;
111
+ export declare function createPermissionServiceProcedureBuilder<TInput, TCtx extends ServiceProcedureContext, Repositories extends RepositoryMap, Services extends ServiceMap, State extends ServiceProcedureState = Record<string, never>>(host: PermissionServiceProcedureHost<Repositories, Services>, config: ProcedureBuilderConfig<Repositories, Services>): PermissionServiceProcedureBuilder<TInput, TCtx, Repositories, Services, State>;
112
+ export {};
@@ -0,0 +1,289 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createServiceProcedureBuilder = createServiceProcedureBuilder;
4
+ exports.createPermissionServiceProcedureBuilder = createPermissionServiceProcedureBuilder;
5
+ const neverthrow_1 = require("neverthrow");
6
+ const DEFAULT_CONTEXT_FILTER_INCLUDE = [
7
+ "user",
8
+ ];
9
+ function isServerResult(value) {
10
+ return (typeof value === "object" &&
11
+ value !== null &&
12
+ "isErr" in value &&
13
+ typeof value.isErr === "function" &&
14
+ "isOk" in value &&
15
+ typeof value.isOk === "function");
16
+ }
17
+ async function normalizeProcedureResult(result) {
18
+ const resolved = await result;
19
+ return isServerResult(resolved) ? resolved : (0, neverthrow_1.ok)(resolved);
20
+ }
21
+ function assertUniqueStepName(steps, stepName) {
22
+ if (steps.some((step) => step.stepName === stepName)) {
23
+ throw new Error(`Duplicate service procedure step name: ${stepName}`);
24
+ }
25
+ }
26
+ function hasStepName(steps, stepName) {
27
+ return steps.some((step) => step.stepName === stepName);
28
+ }
29
+ function getContextFilterInclude(include = DEFAULT_CONTEXT_FILTER_INCLUDE) {
30
+ return {
31
+ user: include.includes("user"),
32
+ organization: include.includes("organization"),
33
+ team: include.includes("team"),
34
+ };
35
+ }
36
+ function getFailureStage(code) {
37
+ return code === "FORBIDDEN" || code === "UNAUTHORIZED" ? "forbidden" : "error";
38
+ }
39
+ function logProcedureStage(host, procedureName, ctx, stage, { stepName, durationMs, errorCode, } = {}) {
40
+ host.logger.debug({
41
+ procedureName,
42
+ stage,
43
+ stepName,
44
+ durationMs,
45
+ errorCode,
46
+ hasUser: Boolean(ctx.user),
47
+ hasSession: Boolean(ctx.session),
48
+ });
49
+ }
50
+ function createRequireAuthStep(host) {
51
+ return {
52
+ stage: "auth",
53
+ stepName: "auth",
54
+ run: async ({ ctx }) => {
55
+ if (!ctx.user || !ctx.session) {
56
+ return host.error("UNAUTHORIZED", "Unauthorized");
57
+ }
58
+ return (0, neverthrow_1.ok)(true);
59
+ },
60
+ };
61
+ }
62
+ function createUseStep(stepName, step) {
63
+ return {
64
+ stage: "use",
65
+ stepName,
66
+ run: async (args) => normalizeProcedureResult(step(args)),
67
+ };
68
+ }
69
+ function createInputStep(stepName, step) {
70
+ return {
71
+ stage: "input",
72
+ stepName,
73
+ run: async (args) => normalizeProcedureResult(step(args)),
74
+ };
75
+ }
76
+ function createContextFilterStep(host, include) {
77
+ const contextInclude = getContextFilterInclude(include);
78
+ return {
79
+ stage: "input",
80
+ stepName: "contextFilter",
81
+ run: async ({ input, ctx }) => (0, neverthrow_1.ok)(host.addContextFilter(ctx, contextInclude, input)),
82
+ };
83
+ }
84
+ function createAccessStep(host, config) {
85
+ return {
86
+ stage: "access",
87
+ stepName: "access",
88
+ run: async (args) => {
89
+ const typedArgs = args;
90
+ if (!typedArgs.ctx.user || !typedArgs.ctx.session) {
91
+ return host.error("UNAUTHORIZED", "Unauthorized");
92
+ }
93
+ const permissionContext = {
94
+ user: typedArgs.ctx.user,
95
+ session: typedArgs.ctx.session,
96
+ };
97
+ if ("entityStep" in config && typeof config.entityStep === "string") {
98
+ const entities = typedArgs.state[config.entityStep];
99
+ const hasPermission = host.checkPermission(permissionContext, config.action, entities, config.grants);
100
+ if (!hasPermission) {
101
+ return host.error("FORBIDDEN");
102
+ }
103
+ return (0, neverthrow_1.ok)(entities);
104
+ }
105
+ if (typeof config.entities === "function") {
106
+ const resolveEntities = config.entities;
107
+ let loadedEntities;
108
+ const permission = await host.checkPermissionAsync(permissionContext, config.action, async () => {
109
+ const entityResult = await normalizeProcedureResult(resolveEntities(typedArgs));
110
+ if (entityResult.isOk()) {
111
+ loadedEntities = entityResult.value;
112
+ }
113
+ return entityResult;
114
+ }, config.grants);
115
+ if (permission.isErr()) {
116
+ return permission;
117
+ }
118
+ if (!permission.value) {
119
+ return host.error("FORBIDDEN");
120
+ }
121
+ return (0, neverthrow_1.ok)(loadedEntities);
122
+ }
123
+ const entities = config.entities;
124
+ const hasPermission = host.checkPermission(permissionContext, config.action, entities, config.grants);
125
+ if (!hasPermission) {
126
+ return host.error("FORBIDDEN");
127
+ }
128
+ return (0, neverthrow_1.ok)(entities);
129
+ },
130
+ };
131
+ }
132
+ function createProcedureHandler(host, config, handler) {
133
+ return async (input, ctx) => host.throwableAsync(async () => {
134
+ const state = {};
135
+ const startTime = Date.now();
136
+ const typedCtx = ctx;
137
+ let currentInput = input;
138
+ logProcedureStage(host, config.name, typedCtx, "start");
139
+ try {
140
+ for (const step of config.steps) {
141
+ const stepResult = await step.run({
142
+ input: currentInput,
143
+ ctx: typedCtx,
144
+ state,
145
+ repository: host.repository,
146
+ service: host.service,
147
+ logger: host.logger,
148
+ });
149
+ if (stepResult.isErr()) {
150
+ logProcedureStage(host, config.name, typedCtx, getFailureStage(stepResult.error.code), {
151
+ stepName: step.stepName,
152
+ durationMs: Date.now() - startTime,
153
+ errorCode: stepResult.error.code,
154
+ });
155
+ return stepResult;
156
+ }
157
+ state[step.stepName] = stepResult.value;
158
+ if (step.stage === "input") {
159
+ currentInput = stepResult.value;
160
+ }
161
+ if (step.stage === "auth") {
162
+ logProcedureStage(host, config.name, typedCtx, "auth_passed", {
163
+ stepName: step.stepName,
164
+ });
165
+ }
166
+ if (step.stage === "access") {
167
+ logProcedureStage(host, config.name, typedCtx, "access_passed", {
168
+ stepName: step.stepName,
169
+ });
170
+ }
171
+ }
172
+ const handlerResult = await normalizeProcedureResult(handler({
173
+ input: currentInput,
174
+ ctx: ctx,
175
+ state: state,
176
+ repository: host.repository,
177
+ service: host.service,
178
+ logger: host.logger,
179
+ }));
180
+ if (handlerResult.isErr()) {
181
+ logProcedureStage(host, config.name, typedCtx, getFailureStage(handlerResult.error.code), {
182
+ durationMs: Date.now() - startTime,
183
+ errorCode: handlerResult.error.code,
184
+ });
185
+ return handlerResult;
186
+ }
187
+ logProcedureStage(host, config.name, typedCtx, "success", {
188
+ durationMs: Date.now() - startTime,
189
+ });
190
+ return handlerResult;
191
+ }
192
+ catch (error) {
193
+ const serverError = host.handleUnknownError(error);
194
+ logProcedureStage(host, config.name, typedCtx, getFailureStage(serverError.code), {
195
+ durationMs: Date.now() - startTime,
196
+ errorCode: serverError.code,
197
+ });
198
+ throw error;
199
+ }
200
+ });
201
+ }
202
+ function createServiceProcedureBuilder(host, config) {
203
+ function addContextFilter(include) {
204
+ const steps = hasStepName(config.steps, "auth")
205
+ ? config.steps
206
+ : [...config.steps, createRequireAuthStep(host)];
207
+ assertUniqueStepName(steps, "contextFilter");
208
+ return createServiceProcedureBuilder(host, {
209
+ ...config,
210
+ steps: [...steps, createContextFilterStep(host, include)],
211
+ });
212
+ }
213
+ const builder = {
214
+ use(stepName, step) {
215
+ assertUniqueStepName(config.steps, stepName);
216
+ return createServiceProcedureBuilder(host, {
217
+ ...config,
218
+ steps: [...config.steps, createUseStep(stepName, step)],
219
+ });
220
+ },
221
+ mapInput(stepName, step) {
222
+ assertUniqueStepName(config.steps, stepName);
223
+ return createServiceProcedureBuilder(host, {
224
+ ...config,
225
+ steps: [...config.steps, createInputStep(stepName, step)],
226
+ });
227
+ },
228
+ addContextFilter,
229
+ requireAuth() {
230
+ assertUniqueStepName(config.steps, "auth");
231
+ return createServiceProcedureBuilder(host, {
232
+ ...config,
233
+ steps: [...config.steps, createRequireAuthStep(host)],
234
+ });
235
+ },
236
+ handle(handler) {
237
+ return createProcedureHandler(host, config, handler);
238
+ },
239
+ };
240
+ return builder;
241
+ }
242
+ function createPermissionServiceProcedureBuilder(host, config) {
243
+ function addContextFilter(include) {
244
+ const steps = hasStepName(config.steps, "auth")
245
+ ? config.steps
246
+ : [...config.steps, createRequireAuthStep(host)];
247
+ assertUniqueStepName(steps, "contextFilter");
248
+ return createPermissionServiceProcedureBuilder(host, {
249
+ ...config,
250
+ steps: [...steps, createContextFilterStep(host, include)],
251
+ });
252
+ }
253
+ function access(accessConfig) {
254
+ assertUniqueStepName(config.steps, "access");
255
+ return createPermissionServiceProcedureBuilder(host, {
256
+ ...config,
257
+ steps: [...config.steps, createAccessStep(host, accessConfig)],
258
+ });
259
+ }
260
+ const builder = {
261
+ use(stepName, step) {
262
+ assertUniqueStepName(config.steps, stepName);
263
+ return createPermissionServiceProcedureBuilder(host, {
264
+ ...config,
265
+ steps: [...config.steps, createUseStep(stepName, step)],
266
+ });
267
+ },
268
+ mapInput(stepName, step) {
269
+ assertUniqueStepName(config.steps, stepName);
270
+ return createPermissionServiceProcedureBuilder(host, {
271
+ ...config,
272
+ steps: [...config.steps, createInputStep(stepName, step)],
273
+ });
274
+ },
275
+ addContextFilter,
276
+ requireAuth() {
277
+ assertUniqueStepName(config.steps, "auth");
278
+ return createPermissionServiceProcedureBuilder(host, {
279
+ ...config,
280
+ steps: [...config.steps, createRequireAuthStep(host)],
281
+ });
282
+ },
283
+ access,
284
+ handle(handler) {
285
+ return createProcedureHandler(host, config, handler);
286
+ },
287
+ };
288
+ return builder;
289
+ }
@@ -32,6 +32,7 @@ export declare class BaseRepository<O extends LibSQLDatabase<any>, S extends Rec
32
32
  getConditionBuilder(): ConditionBuilder;
33
33
  getConditionBuilder(table: undefined): ConditionBuilder;
34
34
  getConditionBuilder<TTable extends SQLiteTableWithColumns<any>>(table: TTable): TableConditionBuilder<TTable>;
35
+ throwableQuery<T>(fn: () => Promise<T>): ServerResultAsync<T>;
35
36
  withPagination<TQuery>(query: TQuery, { page, limit }: Pick<QueryInput, "page" | "limit">): TQuery;
36
37
  withSorting<TTable extends SQLiteTableWithColumns<any>, TQuery>(query: TQuery, { sort, order }: Pick<QueryInput, "sort" | "order">, table?: TTable): TQuery;
37
38
  withSortingAndPagination<TTable extends SQLiteTableWithColumns<any>, TQuery>(query: TQuery, { sort, order, page, limit }: Pick<QueryInput, "sort" | "order" | "page" | "limit">, table?: TTable): TQuery;
@@ -3,11 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BaseExternaRepository = exports.BaseTableRepository = exports.BaseRepository = exports.arrayContains = exports.TableConditionBuilder = exports.ConditionBuilder = void 0;
4
4
  const drizzle_orm_1 = require("drizzle-orm");
5
5
  const neverthrow_1 = require("neverthrow");
6
- const base_abstract_1 = require("./base.abstract");
7
- const base_dto_1 = require("./base.dto");
6
+ const errors_1 = require("../../utils/errors");
8
7
  const applyPagination_1 = require("../utils/applyPagination");
9
8
  const applySorting_1 = require("../utils/applySorting");
10
9
  const getConditionsFromFilters_1 = require("../utils/getConditionsFromFilters");
10
+ const base_abstract_1 = require("./base.abstract");
11
+ const base_dto_1 = require("./base.dto");
11
12
  class ConditionBuilder {
12
13
  conditions;
13
14
  constructor(conditions = []) {
@@ -66,6 +67,15 @@ class BaseRepository extends base_abstract_1.Base {
66
67
  }
67
68
  return new TableConditionBuilder(table);
68
69
  }
70
+ throwableQuery(fn) {
71
+ return this.throwablePromise(() => fn(), (error) => new errors_1.ServerError({
72
+ code: "INTERNAL_SERVER_ERROR",
73
+ layer: "repository",
74
+ layerName: this.constructor.name,
75
+ message: "Database query failed",
76
+ cause: error,
77
+ }));
78
+ }
69
79
  withPagination(query, { page, limit }) {
70
80
  return (0, applyPagination_1.applyPagination)(query, limit, page);
71
81
  }