@ai0x0/utils 0.1.2 → 0.2.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.
Files changed (29) hide show
  1. package/SKILL.md +3 -2
  2. package/es/backend/route-operation/delete-operation.d.ts +5 -9
  3. package/es/backend/route-operation/get-list-operation.d.ts +5 -9
  4. package/es/backend/route-operation/get-operation.d.ts +5 -9
  5. package/es/backend/route-operation/index.d.ts +2 -0
  6. package/es/backend/route-operation/index.js +4 -1
  7. package/es/backend/route-operation/operation-common.d.ts +12 -0
  8. package/es/backend/route-operation/operation-common.js +2 -1
  9. package/es/backend/route-operation/post-operation.d.ts +5 -9
  10. package/es/backend/route-operation/put-operation.d.ts +5 -9
  11. package/es/backend/route-operation/write-operation-core.js +30 -25
  12. package/es/backend/schemas/index.d.ts +245 -235
  13. package/es/backend/schemas/index.js +15 -5
  14. package/es/backend/sqlite/schemas/index.d.ts +3 -0
  15. package/es/backend/sqlite/schemas/index.js +15 -5
  16. package/lib/backend/route-operation/delete-operation.d.ts +5 -9
  17. package/lib/backend/route-operation/get-list-operation.d.ts +5 -9
  18. package/lib/backend/route-operation/get-operation.d.ts +5 -9
  19. package/lib/backend/route-operation/index.d.ts +2 -0
  20. package/lib/backend/route-operation/operation-common.d.ts +12 -0
  21. package/lib/backend/route-operation/operation-common.js +1 -1
  22. package/lib/backend/route-operation/post-operation.d.ts +5 -9
  23. package/lib/backend/route-operation/put-operation.d.ts +5 -9
  24. package/lib/backend/route-operation/write-operation-core.js +9 -2
  25. package/lib/backend/schemas/index.d.ts +245 -235
  26. package/lib/backend/schemas/index.js +7 -6
  27. package/lib/backend/sqlite/schemas/index.d.ts +3 -0
  28. package/lib/backend/sqlite/schemas/index.js +6 -2
  29. package/package.json +1 -1
@@ -8,7 +8,9 @@ import { z } from "zod";
8
8
  import { pgTable, timestamp, uuid } from "drizzle-orm/pg-core";
9
9
  import { createInsertSchema, createSelectSchema, createUpdateSchema } from "drizzle-zod";
10
10
 
11
- //============================基本字段============================//
11
+ // =============================================================================
12
+ // 基本字段 —— 每张表都注入的那几列
13
+ // =============================================================================
12
14
  var timestamptz = function timestamptz(name) {
13
15
  return timestamp(name, {
14
16
  withTimezone: true
@@ -67,7 +69,9 @@ export var BASIC_UPDATE_OMIT = {
67
69
  updatedAt: true
68
70
  };
69
71
 
70
- //============================列表查询字段============================//
72
+ // =============================================================================
73
+ // 列表查询字段
74
+ // =============================================================================
71
75
  export var queryListSchema = function queryListSchema(schema) {
72
76
  return z.object({
73
77
  current: z.string().optional().default("1"),
@@ -84,7 +88,9 @@ export var queryListSchema = function queryListSchema(schema) {
84
88
  }).merge(schema);
85
89
  };
86
90
 
87
- //============================列表返回字段============================//
91
+ // =============================================================================
92
+ // 列表返回字段
93
+ // =============================================================================
88
94
  export var listBodySchema = function listBodySchema(schema) {
89
95
  return z.object({
90
96
  total: z.number(),
@@ -92,7 +98,9 @@ export var listBodySchema = function listBodySchema(schema) {
92
98
  });
93
99
  };
94
100
 
95
- //============================创建一个pg表============================//
101
+ // =============================================================================
102
+ // 建表 —— 表 + 5 份 zod schema
103
+ // =============================================================================
96
104
  /**
97
105
  * 基于 drizzle + drizzle-zod 快速生成带基础字段(id / 创建时间等)的
98
106
  * 表定义以及 select / insert / update / query / list zod schema。
@@ -100,10 +108,12 @@ export var listBodySchema = function listBodySchema(schema) {
100
108
  export var createTableSchema = function createTableSchema(_ref) {
101
109
  var name = _ref.name,
102
110
  columns = _ref.columns,
111
+ serverColumns = _ref.serverColumns,
103
112
  extraConfig = _ref.extraConfig;
104
- var mergedColumns = _objectSpread(_objectSpread({}, basicFields), columns);
113
+ var mergedColumns = _objectSpread(_objectSpread(_objectSpread({}, basicFields), serverColumns), columns);
105
114
  var table = pgTable(name, mergedColumns, extraConfig);
106
115
  var selectSchema = createSelectSchema(table);
116
+ // 只从 columns 推 —— basicFields 与 serverColumns 都由服务端写,不该出现在请求体里。
107
117
  var insertSchema = createInsertSchema(pgTable(name, columns));
108
118
  var updateSchema = createUpdateSchema(pgTable(name, _objectSpread({
109
119
  id: uuid("id")
@@ -119,7 +119,10 @@ export declare const listBodySchema: <T extends z.ZodType<unknown, unknown, z.co
119
119
  */
120
120
  export declare const createTableSchema: <TTableName extends string, TColumnsMap extends Record<string, SQLiteColumnBuilderBase>>(_options: {
121
121
  name: TTableName;
122
+ /** 客户端能写的业务列。insert / update schema 只从这里推。 */
122
123
  columns: TColumnsMap;
124
+ /** 由服务端盖、绝不接受客户端传的业务列(归属、租户 id 这类)。语义与 pg 版一致,见那边的说明。 */
125
+ serverColumns?: Record<string, SQLiteColumnBuilderBase>;
123
126
  extraConfig?: (_self: BuildExtraConfigColumns<TTableName, typeof basicFields & TColumnsMap, "sqlite">) => SQLiteTableExtraConfigValue[];
124
127
  }) => {
125
128
  table: any;
@@ -8,7 +8,9 @@ import { z } from "zod";
8
8
  import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
9
9
  import { createInsertSchema, createSelectSchema, createUpdateSchema } from "drizzle-zod";
10
10
 
11
- //============================基本字段============================//
11
+ // =============================================================================
12
+ // 基本字段 —— 每张表都注入的那几列
13
+ // =============================================================================
12
14
  var timestamp = function timestamp(name) {
13
15
  return integer(name, {
14
16
  mode: "timestamp_ms"
@@ -73,7 +75,9 @@ export var BASIC_UPDATE_OMIT = {
73
75
  updatedAt: true
74
76
  };
75
77
 
76
- //============================列表查询字段============================//
78
+ // =============================================================================
79
+ // 列表查询字段
80
+ // =============================================================================
77
81
  export var queryListSchema = function queryListSchema(schema) {
78
82
  return z.object({
79
83
  current: z.string().optional().default("1"),
@@ -90,7 +94,9 @@ export var queryListSchema = function queryListSchema(schema) {
90
94
  }).merge(schema);
91
95
  };
92
96
 
93
- //============================列表返回字段============================//
97
+ // =============================================================================
98
+ // 列表返回字段
99
+ // =============================================================================
94
100
  export var listBodySchema = function listBodySchema(schema) {
95
101
  return z.object({
96
102
  total: z.number(),
@@ -98,7 +104,9 @@ export var listBodySchema = function listBodySchema(schema) {
98
104
  });
99
105
  };
100
106
 
101
- //============================创建一个sqlite表============================//
107
+ // =============================================================================
108
+ // 建表 —— 表 + 5 份 zod schema
109
+ // =============================================================================
102
110
  /**
103
111
  * 基于 drizzle + drizzle-zod 快速生成带基础字段(id / 创建时间等)的
104
112
  * 表定义以及 select / insert / update / query / list zod schema。
@@ -106,10 +114,12 @@ export var listBodySchema = function listBodySchema(schema) {
106
114
  export var createTableSchema = function createTableSchema(_ref) {
107
115
  var name = _ref.name,
108
116
  columns = _ref.columns,
117
+ serverColumns = _ref.serverColumns,
109
118
  extraConfig = _ref.extraConfig;
110
- var mergedColumns = _objectSpread(_objectSpread({}, basicFields), columns);
119
+ var mergedColumns = _objectSpread(_objectSpread(_objectSpread({}, basicFields), serverColumns), columns);
111
120
  var table = sqliteTable(name, mergedColumns, extraConfig);
112
121
  var selectSchema = createSelectSchema(table);
122
+ // 只从 columns 推 —— basicFields 与 serverColumns 都由服务端写,不该出现在请求体里。
113
123
  var insertSchema = createInsertSchema(sqliteTable(name, columns));
114
124
  var updateSchema = createUpdateSchema(sqliteTable(name, _objectSpread({
115
125
  id: text("id")
@@ -1,16 +1,12 @@
1
1
  import { NodePgDatabase } from "drizzle-orm/node-postgres";
2
- import { NextRequest } from "next/server";
3
2
  import { ZodSchema } from "zod";
4
3
  import { BaseTable } from "../types.js";
5
4
  import { type DeleteOperationOptions as CoreDeleteOperationOptions } from "./operation-core.js";
6
- export type DeleteOperationOptions<TTable extends BaseTable, B extends ZodSchema> = CoreDeleteOperationOptions<TTable, B>;
7
- export declare const createDeleteOperation: ({ db, getSession, }: {
5
+ import type { DefaultSession, SessionGetter } from "./operation-common.js";
6
+ export type DeleteOperationOptions<TTable extends BaseTable, B extends ZodSchema, TSession = DefaultSession> = CoreDeleteOperationOptions<TTable, B, TSession>;
7
+ export declare const createDeleteOperation: <TSession = DefaultSession>({ db, getSession, }: {
8
8
  db?: NodePgDatabase<Record<string, unknown>> | undefined;
9
- getSession(req: NextRequest): Promise<{
10
- userId?: string;
11
- } | undefined>;
9
+ getSession: SessionGetter<TSession>;
12
10
  }) => <B extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> = import("zod").ZodObject<{
13
11
  id: import("zod").ZodString;
14
- }, import("zod/v4/core").$strip>>({ table, schemas, access, openApiOperation, handler, catch: catchHandler, }: CoreDeleteOperationOptions<BaseTable, B, {
15
- userId?: string | undefined;
16
- }>) => import("next-rest-framework").RouteOperationDefinition<"DELETE">;
12
+ }, import("zod/v4/core").$strip>>({ table, schemas, access, openApiOperation, handler, catch: catchHandler, }: CoreDeleteOperationOptions<BaseTable, B, TSession>) => import("next-rest-framework").RouteOperationDefinition<"DELETE">;
@@ -1,14 +1,10 @@
1
1
  import { NodePgDatabase } from "drizzle-orm/node-postgres";
2
- import { NextRequest } from "next/server";
3
2
  import { ZodSchema } from "zod";
4
3
  import { BaseTable, GetListRelations } from "../types.js";
5
4
  import { type GetListOperationOptions as CoreGetListOperationOptions } from "./operation-core.js";
6
- export type GetListOperationOptions<T extends ZodSchema, Q extends ZodSchema, TTable extends BaseTable> = CoreGetListOperationOptions<T, Q, TTable, GetListRelations>;
7
- export declare const createGetListOperation: ({ db, getSession, }: {
5
+ import type { DefaultSession, SessionGetter } from "./operation-common.js";
6
+ export type GetListOperationOptions<T extends ZodSchema, Q extends ZodSchema, TTable extends BaseTable, TSession = DefaultSession> = CoreGetListOperationOptions<T, Q, TTable, GetListRelations, TSession>;
7
+ export declare const createGetListOperation: <TSession = DefaultSession>({ db, getSession, }: {
8
8
  db?: NodePgDatabase<Record<string, unknown>> | undefined;
9
- getSession(req: NextRequest): Promise<{
10
- userId?: string;
11
- } | undefined>;
12
- }) => <T extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>, Q extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>({ schemas, access, table, openApiOperation, relations, jsonArrayFields, setParams, handler, catch: catchHandler, }: CoreGetListOperationOptions<T, Q, BaseTable, GetListRelations, {
13
- userId?: string | undefined;
14
- }>) => import("next-rest-framework").RouteOperationDefinition<"GET">;
9
+ getSession: SessionGetter<TSession>;
10
+ }) => <T extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>, Q extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>({ schemas, access, table, openApiOperation, relations, jsonArrayFields, setParams, handler, catch: catchHandler, }: CoreGetListOperationOptions<T, Q, BaseTable, GetListRelations, TSession>) => import("next-rest-framework").RouteOperationDefinition<"GET">;
@@ -1,14 +1,10 @@
1
1
  import { NodePgDatabase } from "drizzle-orm/node-postgres";
2
- import { NextRequest } from "next/server";
3
2
  import { ZodSchema } from "zod";
4
3
  import { BaseTable, GetListRelations } from "../types.js";
5
4
  import { type GetOperationOptions as CoreGetOperationOptions } from "./operation-core.js";
6
- export type GetOperationOptions<T extends ZodSchema, Q extends ZodSchema, TTable extends BaseTable> = CoreGetOperationOptions<T, Q, TTable, GetListRelations>;
7
- export declare const createGetOperation: ({ getSession, db, }: {
5
+ import type { DefaultSession, SessionGetter } from "./operation-common.js";
6
+ export type GetOperationOptions<T extends ZodSchema, Q extends ZodSchema, TTable extends BaseTable, TSession = DefaultSession> = CoreGetOperationOptions<T, Q, TTable, GetListRelations, TSession>;
7
+ export declare const createGetOperation: <TSession = DefaultSession>({ getSession, db, }: {
8
8
  db?: NodePgDatabase<Record<string, unknown>> | undefined;
9
- getSession(req: NextRequest): Promise<{
10
- userId?: string;
11
- } | undefined>;
12
- }) => <T extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>, Q extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>({ schemas, access, table, openApiOperation, relations, setParams, jsonArrayFields, handler, catch: catchHandler, }: CoreGetOperationOptions<T, Q, BaseTable, GetListRelations, {
13
- userId?: string | undefined;
14
- }>) => import("next-rest-framework").RouteOperationDefinition<"GET">;
9
+ getSession: SessionGetter<TSession>;
10
+ }) => <T extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>, Q extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>({ schemas, access, table, openApiOperation, relations, setParams, jsonArrayFields, handler, catch: catchHandler, }: CoreGetOperationOptions<T, Q, BaseTable, GetListRelations, TSession>) => import("next-rest-framework").RouteOperationDefinition<"GET">;
@@ -4,3 +4,5 @@ export * from "./delete-operation.js";
4
4
  export * from "./post-operation.js";
5
5
  export * from "./put-operation.js";
6
6
  export * from "./open-api-operation.js";
7
+ export type { AccessDenial, AccessOptions, DefaultSession, HttpMethod, SessionGetter, } from "./operation-common.js";
8
+ export type { ScopeCondition, ScopeValue } from "../scope.js";
@@ -44,6 +44,18 @@ export interface AccessOptions<TSession = DefaultSession> {
44
44
  session: TSession;
45
45
  method: HttpMethod;
46
46
  }) => boolean | AccessDenial | Promise<boolean | AccessDenial>;
47
+ /**
48
+ * 新建(POST)时额外要盖在行上的列。归属列由 `scope` 盖,这里管别的服务端字段 ——
49
+ * 最典型的就是「谁建的」:归属列一旦不是 `creatorId`(比如换成 `ownerId`),作者就没人写了,
50
+ * 而 `setBody` 只能返回请求体 schema 里有的字段,`creatorId` 不在里面。
51
+ *
52
+ * 与归属戳同一条不变量:**最后展开,客户端覆盖不了**。所以这里能安全地盖任何服务端字段,
53
+ * 不必担心请求体里塞一个同名键把它顶掉。
54
+ *
55
+ * 库不替业务猜要盖什么(哪张表有 creatorId、要不要记作者,都是业务的事),所以给的是钩子
56
+ * 而不是默认行为。
57
+ */
58
+ stamp?: (session: TSession) => Record<string, unknown>;
47
59
  }
48
60
  /**
49
61
  * 把会话读取包成「本次请求最多取一次」的取值器。
@@ -42,7 +42,7 @@ async function resolveAccess({
42
42
  }) {
43
43
  var _a;
44
44
  const wantsScope = Boolean(access == null ? void 0 : access.scope) || ((access == null ? void 0 : access.byCreator) ?? true);
45
- const session = wantsScope || (access == null ? void 0 : access.can) ? await loadSession() : void 0;
45
+ const session = wantsScope || (access == null ? void 0 : access.can) || (access == null ? void 0 : access.stamp) ? await loadSession() : void 0;
46
46
  if (access == null ? void 0 : access.can) {
47
47
  if (!session) {
48
48
  throw new import_errors.HttpError(401, "未登录");
@@ -1,14 +1,10 @@
1
1
  import { PgTable } from "drizzle-orm/pg-core";
2
2
  import { NodePgDatabase } from "drizzle-orm/node-postgres";
3
- import { NextRequest } from "next/server";
4
3
  import { ZodSchema } from "zod";
5
4
  import { type PostOperationOptions as CorePostOperationOptions } from "./operation-core.js";
6
- export type PostOperationOptions<IB extends ZodSchema, OB extends ZodSchema, TTable extends PgTable> = CorePostOperationOptions<IB, OB, TTable>;
7
- export declare const createPostOperation: ({ getSession, db, }: {
5
+ import type { DefaultSession, SessionGetter } from "./operation-common.js";
6
+ export type PostOperationOptions<IB extends ZodSchema, OB extends ZodSchema, TTable extends PgTable, TSession = DefaultSession> = CorePostOperationOptions<IB, OB, TTable, TSession>;
7
+ export declare const createPostOperation: <TSession = DefaultSession>({ getSession, db, }: {
8
8
  db?: NodePgDatabase<Record<string, unknown>> | undefined;
9
- getSession(req: NextRequest): Promise<{
10
- userId?: string;
11
- } | undefined>;
12
- }) => <IB extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>, OB extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>({ schemas, access, contentType, openApiOperation, parseBody, setBody, table, handler, catch: catchHandler, }: CorePostOperationOptions<IB, OB, PgTable<import("drizzle-orm/pg-core").TableConfig>, {
13
- userId?: string | undefined;
14
- }>) => import("next-rest-framework").RouteOperationDefinition<"POST">;
9
+ getSession: SessionGetter<TSession>;
10
+ }) => <IB extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>, OB extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>({ schemas, access, contentType, openApiOperation, parseBody, setBody, table, handler, catch: catchHandler, }: CorePostOperationOptions<IB, OB, PgTable<import("drizzle-orm/pg-core").TableConfig>, TSession>) => import("next-rest-framework").RouteOperationDefinition<"POST">;
@@ -1,14 +1,10 @@
1
1
  import { PgTable } from "drizzle-orm/pg-core";
2
2
  import { NodePgDatabase } from "drizzle-orm/node-postgres";
3
- import { NextRequest } from "next/server";
4
3
  import { ZodSchema } from "zod";
5
4
  import { type PutOperationOptions as CorePutOperationOptions } from "./operation-core.js";
6
- export type PutOperationOptions<IB extends ZodSchema, OB extends ZodSchema, TTable extends PgTable> = CorePutOperationOptions<IB, OB, TTable>;
7
- export declare const createPutOperation: ({ getSession, db, }: {
8
- getSession(req: NextRequest): Promise<{
9
- userId?: string;
10
- } | undefined>;
5
+ import type { DefaultSession, SessionGetter } from "./operation-common.js";
6
+ export type PutOperationOptions<IB extends ZodSchema, OB extends ZodSchema, TTable extends PgTable, TSession = DefaultSession> = CorePutOperationOptions<IB, OB, TTable, TSession>;
7
+ export declare const createPutOperation: <TSession = DefaultSession>({ getSession, db, }: {
8
+ getSession: SessionGetter<TSession>;
11
9
  db?: NodePgDatabase<Record<string, unknown>> | undefined;
12
- }) => <IB extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>, OB extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>({ schemas, access, openApiOperation, table, setBody, handler, catch: catchHandler, }: CorePutOperationOptions<IB, OB, PgTable<import("drizzle-orm/pg-core").TableConfig>, {
13
- userId?: string | undefined;
14
- }>) => import("next-rest-framework").RouteOperationDefinition<"PUT">;
10
+ }) => <IB extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>, OB extends ZodSchema<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>({ schemas, access, openApiOperation, table, setBody, handler, catch: catchHandler, }: CorePutOperationOptions<IB, OB, PgTable<import("drizzle-orm/pg-core").TableConfig>, TSession>) => import("next-rest-framework").RouteOperationDefinition<"PUT">;
@@ -62,15 +62,22 @@ function createPostOperationFactory({
62
62
  status: 200
63
63
  }
64
64
  ]).handler(async (req) => {
65
+ var _a;
65
66
  try {
66
- const { scope } = await (0, import_operation_common.resolveAccess)({
67
+ const { scope, session } = await (0, import_operation_common.resolveAccess)({
67
68
  access,
68
69
  loadSession: (0, import_operation_common.sessionLoader)(getSession, req),
69
70
  method: "POST"
70
71
  });
71
72
  const body = await (0, import_operation_common.readPostBody)(req, { contentType, parseBody });
72
73
  const extraBody = await (setBody == null ? void 0 : setBody(req)) || {};
73
- const params = { ...body, ...extraBody, ...scopeStamp(scope) };
74
+ const stamped = session === void 0 ? {} : ((_a = access == null ? void 0 : access.stamp) == null ? void 0 : _a.call(access, session)) ?? {};
75
+ const params = {
76
+ ...body,
77
+ ...extraBody,
78
+ ...stamped,
79
+ ...scopeStamp(scope)
80
+ };
74
81
  const raw = table && db ? (await createAction({
75
82
  bodySchema: schemas.body,
76
83
  db,