@wordrhyme/auto-crud-server 0.2.0 → 0.4.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.
package/dist/index.d.cts CHANGED
@@ -1,8 +1,9 @@
1
- import * as _trpc_server12 from "@trpc/server";
2
- import superjson from "superjson";
1
+ import * as _trpc_server5 from "@trpc/server";
3
2
  import { PostgresJsDatabase } from "drizzle-orm/postgres-js";
4
- import { z } from "zod";
3
+ import * as node_modules__trpc_server_dist_unstable_core_do_not_import_d_CjQPvBRI_mjs0 from "node_modules/@trpc/server/dist/unstable-core-do-not-import.d-CjQPvBRI.mjs";
4
+ import { SQL } from "drizzle-orm";
5
5
  import { PgTable } from "drizzle-orm/pg-core";
6
+ import { z } from "zod";
6
7
 
7
8
  //#region src/trpc.d.ts
8
9
  /**
@@ -12,161 +13,326 @@ import { PgTable } from "drizzle-orm/pg-core";
12
13
  interface Context {
13
14
  db: PostgresJsDatabase<Record<string, never>>;
14
15
  }
15
- declare const t: _trpc_server12.TRPCRootObject<Context, object, {
16
- transformer: typeof superjson;
17
- }, {
18
- ctx: Context;
19
- meta: object;
20
- errorShape: _trpc_server12.TRPCDefaultErrorShape;
21
- transformer: true;
22
- }>;
23
- declare const router: _trpc_server12.TRPCRouterBuilder<{
16
+ declare const router: _trpc_server5.TRPCRouterBuilder<{
24
17
  ctx: Context;
25
18
  meta: object;
26
- errorShape: _trpc_server12.TRPCDefaultErrorShape;
19
+ errorShape: _trpc_server5.TRPCDefaultErrorShape;
27
20
  transformer: true;
28
21
  }>;
29
- declare const publicProcedure: _trpc_server12.TRPCProcedureBuilder<Context, object, object, _trpc_server12.TRPCUnsetMarker, _trpc_server12.TRPCUnsetMarker, _trpc_server12.TRPCUnsetMarker, _trpc_server12.TRPCUnsetMarker, false>;
30
- type AnyProcedure = typeof t.procedure;
22
+ declare const publicProcedure: _trpc_server5.TRPCProcedureBuilder<Context, object, object, _trpc_server5.TRPCUnsetMarker, _trpc_server5.TRPCUnsetMarker, _trpc_server5.TRPCUnsetMarker, _trpc_server5.TRPCUnsetMarker, false>;
31
23
  //#endregion
32
- //#region src/routers/_factory.d.ts
24
+ //#region src/types/config.d.ts
25
+ type CrudOperation = "list" | "get" | "create" | "update" | "delete" | "deleteMany" | "updateMany";
26
+ type WriteOperation = "create" | "update";
27
+ type AnyProcedure = any;
28
+ interface SoftDeleteConfig {
29
+ /** 软删除标记列名 */
30
+ column: string;
31
+ /**
32
+ * 删除时设置的值
33
+ * - 默认: () => new Date()
34
+ * - 可自定义为其他值,如 true(用于 isDeleted 布尔字段)
35
+ */
36
+ value?: () => unknown;
37
+ }
33
38
  /**
34
- * 授权回调类型
35
- * 返回 true 允许操作,返回 false 或抛出错误拒绝操作
39
+ * 软删除配置类型
40
+ * - string: 列名(使用默认值 new Date())
41
+ * - boolean: true 表示使用默认列名 'deletedAt'
42
+ * - SoftDeleteConfig: 完整配置
36
43
  */
37
- type AuthorizeCallback = (ctx: {
38
- operation: "list" | "get" | "create" | "update" | "delete" | "deleteMany" | "updateMany";
39
- input?: unknown;
40
- }) => boolean | Promise<boolean>;
44
+ type SoftDeleteOption = string | boolean | SoftDeleteConfig;
41
45
  /**
42
- * CRUD Router 配置
46
+ * 列表查询输入类型
43
47
  */
44
- interface CrudRouterConfig {
48
+ interface ListInput {
49
+ page: number;
50
+ perPage: number;
51
+ sort?: Array<{
52
+ id: string;
53
+ desc: boolean;
54
+ }>;
55
+ filters?: Array<{
56
+ id: string;
57
+ value: string | string[];
58
+ variant: string;
59
+ operator: string;
60
+ filterId: string;
61
+ }>;
62
+ joinOperator: "and" | "or";
63
+ }
64
+ /**
65
+ * 列表查询结果类型
66
+ */
67
+ interface ListResult<TSelect> {
68
+ data: TSelect[];
69
+ total: number;
70
+ page: number;
71
+ perPage: number;
72
+ pageCount: number;
73
+ }
74
+ /**
75
+ * CRUD 生命周期钩子
76
+ *
77
+ * @example
78
+ * hooks: {
79
+ * beforeCreate: async (ctx, data) => {
80
+ * // 修改数据
81
+ * return { ...data, slug: slugify(data.title) };
82
+ * },
83
+ * afterCreate: async (ctx, created) => {
84
+ * // 发送通知
85
+ * await sendNotification(created);
86
+ * },
87
+ * }
88
+ */
89
+ interface CrudHooks<TContext = unknown> {
90
+ /**
91
+ * 列表查询前
92
+ * 可修改查询参数
93
+ */
94
+ beforeList?: (ctx: TContext, input: ListInput) => ListInput | void | Promise<ListInput | void>;
95
+ /**
96
+ * 列表查询后
97
+ * 可修改返回结果
98
+ */
99
+ afterList?: <TSelect>(ctx: TContext, result: ListResult<TSelect>) => ListResult<TSelect> | void | Promise<ListResult<TSelect> | void>;
100
+ /**
101
+ * 单条查询前
102
+ */
103
+ beforeGet?: (ctx: TContext, id: string) => void | Promise<void>;
104
+ /**
105
+ * 单条查询后
106
+ * 可修改返回结果
107
+ */
108
+ afterGet?: <TSelect>(ctx: TContext, result: TSelect | null) => TSelect | null | void | Promise<TSelect | null | void>;
109
+ /**
110
+ * 创建前
111
+ * 可修改输入数据,返回新数据或抛出错误阻止创建
112
+ */
113
+ beforeCreate?: <TInsert>(ctx: TContext, data: TInsert) => TInsert | void | Promise<TInsert | void>;
114
+ /**
115
+ * 创建后
116
+ * 用于副作用(日志、通知、同步等)
117
+ */
118
+ afterCreate?: <TSelect>(ctx: TContext, created: TSelect) => void | Promise<void>;
119
+ /**
120
+ * 更新前
121
+ * 可修改输入数据,existing 为更新前的记录
122
+ */
123
+ beforeUpdate?: <TUpdate, TSelect>(ctx: TContext, id: string, data: TUpdate, existing: TSelect) => TUpdate | void | Promise<TUpdate | void>;
124
+ /**
125
+ * 更新后
126
+ */
127
+ afterUpdate?: <TSelect>(ctx: TContext, updated: TSelect) => void | Promise<void>;
128
+ /**
129
+ * 删除前
130
+ * existing 为删除前的记录,可抛出错误阻止删除
131
+ */
132
+ beforeDelete?: <TSelect>(ctx: TContext, id: string, existing: TSelect) => void | Promise<void>;
133
+ /**
134
+ * 删除后
135
+ */
136
+ afterDelete?: <TSelect>(ctx: TContext, deleted: TSelect) => void | Promise<void>;
137
+ /**
138
+ * 批量删除前
139
+ */
140
+ beforeDeleteMany?: (ctx: TContext, ids: string[]) => void | Promise<void>;
141
+ /**
142
+ * 批量删除后
143
+ */
144
+ afterDeleteMany?: (ctx: TContext, result: {
145
+ deleted: number;
146
+ }) => void | Promise<void>;
147
+ /**
148
+ * 批量更新前
149
+ * 可修改输入数据
150
+ */
151
+ beforeUpdateMany?: <TUpdate>(ctx: TContext, ids: string[], data: TUpdate) => TUpdate | void | Promise<TUpdate | void>;
152
+ /**
153
+ * 批量更新后
154
+ */
155
+ afterUpdateMany?: (ctx: TContext, result: {
156
+ updated: number;
157
+ }) => void | Promise<void>;
158
+ }
159
+ interface CrudRouterConfigBase<TContext = unknown> {
160
+ /** Drizzle 表定义 */
45
161
  table: PgTable;
46
- selectSchema: z.ZodType;
162
+ /** 查询返回 Schema */
163
+ selectSchema?: z.ZodType;
164
+ /** 创建输入 Schema */
47
165
  insertSchema: z.ZodType;
166
+ /** 更新输入 Schema */
48
167
  updateSchema: z.ZodType;
168
+ /** ID 字段名,默认 "id" */
49
169
  idField?: string;
50
- /**
51
- * 可过滤的列白名单
52
- * 未指定时默认允许所有列(不安全,仅用于开发)
53
- */
170
+ /** 可过滤的列白名单 */
54
171
  filterableColumns?: string[];
172
+ /** 可排序的列白名单 */
173
+ sortableColumns?: string[];
174
+ /** 批量操作的最大数量限制,默认 100 */
175
+ maxBatchSize?: number;
55
176
  /**
56
- * 可排序的列白名单
57
- * 未指定时默认允许所有列(不安全,仅用于开发)
177
+ * 软删除配置
178
+ * 开启后:
179
+ * - delete 操作 → UPDATE ... SET {column} = {value}
180
+ * - deleteMany 操作 → UPDATE ... SET {column} = {value} WHERE id IN (...)
181
+ * - list/get 操作 → 自动添加 WHERE {column} IS NULL
182
+ *
183
+ * @example
184
+ * // 使用默认列名 'deletedAt'
185
+ * softDelete: true
186
+ *
187
+ * // 指定列名
188
+ * softDelete: 'deletedAt'
189
+ *
190
+ * // 完整配置(用于布尔字段)
191
+ * softDelete: { column: 'isDeleted', value: () => true }
58
192
  */
59
- sortableColumns?: string[];
193
+ softDelete?: SoftDeleteOption;
60
194
  /**
61
- * 批量操作的最大数量限制
62
- * 默认: 100
195
+ * 生命周期钩子
196
+ * CRUD 操作前后注入自定义逻辑
197
+ *
198
+ * @example
199
+ * hooks: {
200
+ * beforeCreate: async (ctx, data) => {
201
+ * return { ...data, slug: slugify(data.title) };
202
+ * },
203
+ * afterCreate: async (ctx, created) => {
204
+ * await sendNotification(created);
205
+ * },
206
+ * }
63
207
  */
64
- maxBatchSize?: number;
208
+ hooks?: CrudHooks<TContext>;
209
+ }
210
+ interface DeclarativeConfig<TContext = unknown> extends CrudRouterConfigBase<TContext> {
211
+ mode?: "declarative";
65
212
  /**
66
- * 自定义 procedure(用于注入授权中间件)
67
- * 默认使用 publicProcedure
213
+ * 基础 procedure(认证)
214
+ * 所有操作共用,除非被 guard 拦截
68
215
  */
69
216
  procedure?: AnyProcedure;
70
217
  /**
71
- * 授权回调(简单场景下的快捷授权方式)
72
- * 如果需要更复杂的授权逻辑,建议使用 procedure 注入中间件
218
+ * 操作级守卫(RBAC)
219
+ * scope 之前执行,快速拒绝无权限请求
220
+ *
221
+ * @example
222
+ * guard: (ctx, op) => op === 'delete' ? ctx.user.role === 'admin' : true
223
+ */
224
+ guard?: (ctx: TContext, operation: CrudOperation) => boolean | Promise<boolean>;
225
+ /**
226
+ * 行级过滤(RLS)
227
+ * 返回 SQL 条件,自动注入到 WHERE 子句
228
+ *
229
+ * @example
230
+ * scope: (ctx, table) => eq(table.tenantId, ctx.user.tenantId)
231
+ */
232
+ scope?: (ctx: TContext, table: PgTable, operation: CrudOperation) => SQL | undefined;
233
+ /**
234
+ * 强制注入字段(写入时)
235
+ * 返回的字段会强制覆盖用户输入(防止伪造)
236
+ *
237
+ * @example
238
+ * inject: (ctx) => ({ tenantId: ctx.user.tenantId, createdBy: ctx.user.id })
73
239
  */
74
- authorize?: AuthorizeCallback;
240
+ inject?: (ctx: TContext, operation: WriteOperation) => Record<string, unknown>;
241
+ /**
242
+ * 资源级检查(ABAC)
243
+ * 在 get/update/delete 时,预取资源后调用
244
+ *
245
+ * @example
246
+ * authorize: (ctx, resource, op) => resource.ownerId === ctx.user.id
247
+ */
248
+ authorize?: (ctx: TContext, resource: Record<string, unknown>, operation: CrudOperation) => boolean | Promise<boolean>;
75
249
  }
76
- /**
77
- * 创建通用 CRUD Router
78
- */
79
- declare function createCrudRouter(config: CrudRouterConfig): _trpc_server12.TRPCBuiltRouter<{
250
+ interface FactoryConfig<TContext = unknown> extends CrudRouterConfigBase<TContext> {
251
+ mode: "factory";
252
+ /**
253
+ * Procedure 工厂函数
254
+ * 根据操作类型返回对应的 procedure
255
+ *
256
+ * @example
257
+ * procedureFactory: (op) => {
258
+ * if (['list', 'get'].includes(op)) return publicProcedure;
259
+ * return protectedProcedure.meta({ permission: { action: op, subject: 'Task' } });
260
+ * }
261
+ */
262
+ procedureFactory: (operation: CrudOperation) => AnyProcedure;
263
+ /**
264
+ * 强制注入字段(可选)
265
+ * 如果 DB 层已处理则不需要
266
+ */
267
+ inject?: (ctx: TContext, operation: WriteOperation) => Record<string, unknown>;
268
+ }
269
+ interface ProceduresConfig<TContext = unknown> extends CrudRouterConfigBase<TContext> {
270
+ mode: "procedures";
271
+ /**
272
+ * 按操作指定不同的 procedure
273
+ *
274
+ * @example
275
+ * procedures: {
276
+ * list: publicProcedure,
277
+ * get: publicProcedure,
278
+ * create: editorProcedure,
279
+ * update: editorProcedure,
280
+ * delete: adminProcedure,
281
+ * }
282
+ */
283
+ procedures: Partial<Record<CrudOperation, AnyProcedure>>;
284
+ /**
285
+ * 默认 procedure(未指定操作时使用)
286
+ */
287
+ defaultProcedure?: AnyProcedure;
288
+ /**
289
+ * 强制注入字段(可选)
290
+ */
291
+ inject?: (ctx: TContext, operation: WriteOperation) => Record<string, unknown>;
292
+ }
293
+ type CrudRouterConfig<TContext = unknown> = DeclarativeConfig<TContext> | FactoryConfig<TContext> | ProceduresConfig<TContext>;
294
+ //#endregion
295
+ //#region src/routers/_factory.d.ts
296
+ declare function createCrudRouter<TContext = unknown>(config: CrudRouterConfig<TContext>): node_modules__trpc_server_dist_unstable_core_do_not_import_d_CjQPvBRI_mjs0.Router<{
80
297
  ctx: Context;
81
298
  meta: object;
82
- errorShape: _trpc_server12.TRPCDefaultErrorShape;
299
+ errorShape: _trpc_server5.TRPCDefaultErrorShape;
83
300
  transformer: true;
84
- }, _trpc_server12.TRPCDecorateCreateRouterOptions<{
85
- list: _trpc_server12.TRPCQueryProcedure<{
86
- input: {
87
- page?: number | undefined;
88
- perPage?: number | undefined;
89
- sort?: {
90
- id: string;
91
- desc: boolean;
92
- }[] | undefined;
93
- filters?: {
94
- id: string;
95
- value: string | string[];
96
- variant: "number" | "boolean" | "date" | "text" | "range" | "dateRange" | "select" | "multiSelect";
97
- operator: "iLike" | "notILike" | "eq" | "ne" | "isEmpty" | "isNotEmpty" | "lt" | "lte" | "gt" | "gte" | "isBetween" | "isRelativeToToday" | "inArray" | "notInArray";
98
- filterId: string;
99
- }[] | undefined;
100
- joinOperator?: "and" | "or" | undefined;
101
- };
102
- output: {
103
- data: {
104
- [x: string]: unknown;
105
- }[];
106
- total: number;
107
- page: number;
108
- perPage: number;
109
- pageCount: number;
110
- };
111
- meta: object;
112
- }>;
113
- getById: _trpc_server12.TRPCQueryProcedure<{
114
- input: string;
115
- output: {
116
- [x: string]: unknown;
117
- } | null;
118
- meta: object;
119
- }>;
120
- create: _trpc_server12.TRPCMutationProcedure<{
121
- input: unknown;
122
- output: {
123
- [x: string]: unknown;
124
- } | undefined;
125
- meta: object;
126
- }>;
127
- update: _trpc_server12.TRPCMutationProcedure<{
128
- input: {
129
- id: string;
130
- data: unknown;
131
- };
132
- output: {
133
- [x: string]: unknown;
134
- } | undefined;
135
- meta: object;
136
- }>;
137
- delete: _trpc_server12.TRPCMutationProcedure<{
138
- input: string;
139
- output: {
140
- [x: string]: unknown;
141
- } | undefined;
142
- meta: object;
143
- }>;
144
- deleteMany: _trpc_server12.TRPCMutationProcedure<{
145
- input: string[];
146
- output: {
147
- deleted: number;
148
- };
149
- meta: object;
150
- }>;
151
- updateMany: _trpc_server12.TRPCMutationProcedure<{
152
- input: {
153
- ids: string[];
154
- data: unknown;
155
- };
156
- output: {
157
- updated: number;
158
- };
159
- meta: object;
160
- }>;
161
- }>>;
301
+ }, _trpc_server5.TRPCDecorateCreateRouterOptions<{
302
+ list: any;
303
+ getById: any;
304
+ create: any;
305
+ update: any;
306
+ delete: any;
307
+ deleteMany: any;
308
+ updateMany: any;
309
+ }>> & _trpc_server5.TRPCDecorateCreateRouterOptions<{
310
+ list: any;
311
+ getById: any;
312
+ create: any;
313
+ update: any;
314
+ delete: any;
315
+ deleteMany: any;
316
+ updateMany: any;
317
+ }> & {
318
+ procedures: {
319
+ list: any;
320
+ getById: any;
321
+ create: any;
322
+ update: any;
323
+ delete: any;
324
+ deleteMany: any;
325
+ updateMany: any;
326
+ };
327
+ };
162
328
  //#endregion
163
329
  //#region src/routers/index.d.ts
164
- declare const appRouter: _trpc_server12.TRPCBuiltRouter<{
330
+ declare const appRouter: _trpc_server5.TRPCBuiltRouter<{
165
331
  ctx: Context;
166
332
  meta: object;
167
- errorShape: _trpc_server12.TRPCDefaultErrorShape;
333
+ errorShape: _trpc_server5.TRPCDefaultErrorShape;
168
334
  transformer: true;
169
- }, _trpc_server12.TRPCDecorateCreateRouterOptions<{}>>;
335
+ }, _trpc_server5.TRPCDecorateCreateRouterOptions<{}>>;
170
336
  type AppRouter = typeof appRouter;
171
337
  //#endregion
172
- export { type AnyProcedure, type AppRouter, type AuthorizeCallback, type CrudRouterConfig, appRouter, createCrudRouter, publicProcedure, router };
338
+ export { type AnyProcedure, type AppRouter, type CrudHooks, type CrudOperation, type CrudRouterConfig, type DeclarativeConfig, type FactoryConfig, type ListInput, type ListResult, type ProceduresConfig, type SoftDeleteConfig, type SoftDeleteOption, type WriteOperation, appRouter, createCrudRouter, publicProcedure, router };