@ai0x0/utils 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.
@@ -8,6 +8,18 @@ export type RouteCatch = (error: Error) => Promise<JsonResponse | undefined>;
8
8
  export interface DefaultSession {
9
9
  userId?: string;
10
10
  }
11
+ /**
12
+ * 「这次请求是谁发的」。四个方法都会把它盖进 params.callerId,自定义 handler 判权、署名、
13
+ * 判「是不是本人」一律读它。
14
+ *
15
+ * **不要拿 params.creatorId 当调用者用。** 那是另一件事:POST 上的 creatorId 是**归属戳**
16
+ * (access.scope 指的那一列,换成 ownerId 时它就不叫 creatorId 了),PUT 上的 editorId 是要
17
+ * 写进行里的**审计列**。两者都恰好等于调用者只是默认配置下的巧合。
18
+ *
19
+ * 会话形状是泛型的(调用方可以塞自己的 Scope 进来),所以这里按 DefaultSession 取 userId ——
20
+ * 自定义会话只要带着这个字段就通用。
21
+ */
22
+ export declare function callerIdOf(session: unknown): string | undefined;
11
23
  /**
12
24
  * 会话读取器。泛型化是为了让调用方能在这里一次性解析出「你是谁 + 你现在站在哪个空间 +
13
25
  * 你在那个空间里是什么角色」,后面 access.scope / access.can 都读同一份,不必各自再查一遍库。
@@ -99,7 +111,7 @@ export declare function getDefaultTags<TTable>({ getTableName, table, }: {
99
111
  table?: TTable;
100
112
  }): string[];
101
113
  export type GetOperationParams<Q extends ZodSchema> = z.infer<Q> & Record<string, unknown> & {
102
- creatorId?: string;
114
+ callerId?: string;
103
115
  };
104
116
  /**
105
117
  * 读操作的参数与作用域。
@@ -17,6 +17,21 @@ import { isEmptyScopeValue, NO_SCOPE } from "../scope.js";
17
17
 
18
18
  /** 默认的会话形状。够用于「一条记录属于一个人」的场景。 */
19
19
 
20
+ /**
21
+ * 「这次请求是谁发的」。四个方法都会把它盖进 params.callerId,自定义 handler 判权、署名、
22
+ * 判「是不是本人」一律读它。
23
+ *
24
+ * **不要拿 params.creatorId 当调用者用。** 那是另一件事:POST 上的 creatorId 是**归属戳**
25
+ * (access.scope 指的那一列,换成 ownerId 时它就不叫 creatorId 了),PUT 上的 editorId 是要
26
+ * 写进行里的**审计列**。两者都恰好等于调用者只是默认配置下的巧合。
27
+ *
28
+ * 会话形状是泛型的(调用方可以塞自己的 Scope 进来),所以这里按 DefaultSession 取 userId ——
29
+ * 自定义会话只要带着这个字段就通用。
30
+ */
31
+ export function callerIdOf(session) {
32
+ return session === null || session === void 0 ? void 0 : session.userId;
33
+ }
34
+
20
35
  /**
21
36
  * 会话读取器。泛型化是为了让调用方能在这里一次性解析出「你是谁 + 你现在站在哪个空间 +
22
37
  * 你在那个空间里是什么角色」,后面 access.scope / access.can 都读同一份,不必各自再查一遍库。
@@ -245,6 +260,13 @@ export function getDefaultTags(_ref3) {
245
260
  // 读操作的参数
246
261
  // ==============================================================================
247
262
 
263
+ // callerId 是服务端盖的,**不是** query 里来的:调用方在地址栏上写 `?callerId=别人`
264
+ // 覆盖不了它(下面 getReadParams 里它最后展开)。
265
+ //
266
+ // 这里原先声明的是 `creatorId?: string`,而读操作从来没有填过它 —— 类型说有、运行时没有,
267
+ // 于是 `if (!params.creatorId) throw 401` 这种判权写法编译绿灯、线上对所有人 401。
268
+ // 那个字段已经删掉:要调用者就用 callerId,要按创建者筛就在 query schema 里显式声明一个。
269
+
248
270
  /**
249
271
  * 读操作的参数与作用域。
250
272
  *
@@ -284,6 +306,9 @@ function _getReadParams() {
284
306
  session = _yield$resolveAccess.session;
285
307
  queryParams = schemas.query.parse(Object.fromEntries(new URL(req.url).searchParams));
286
308
  return _context4.abrupt("return", {
309
+ // 这一份**不带 callerId**:它会被当成筛选条件送进查询构造器,而 callerId 不是任何表的列。
310
+ // 列表那边认不出的键会跳过(get-list-query 的 `if (!targetColumn) continue`),但别指望
311
+ // 这条兜底 —— 交给 handler 的那一份在 read-operation-core 里单独拼,见那里。
287
312
  params: _objectSpread(_objectSpread({}, queryParams), extraParams),
288
313
  scope: scope,
289
314
  session: session
@@ -1,11 +1,16 @@
1
1
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
2
  function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function define(t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function value(t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw new Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator.return && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(_typeof(e) + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function stop() { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw new Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function abrupt(t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function complete(t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function finish(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, catch: function _catch(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw new Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; }
3
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
4
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
5
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
7
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
3
8
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
4
9
  function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
5
10
  import { routeOperation, TypedNextResponse } from "next-rest-framework";
6
11
  import { listBodySchema } from "../schemas/index.js";
7
12
  import { createOpenApiOperation } from "./open-api-operation.js";
8
- import { getDefaultTags, getReadParams, handleOperationError } from "./operation-common.js";
13
+ import { callerIdOf, getDefaultTags, getReadParams, handleOperationError } from "./operation-common.js";
9
14
 
10
15
  // ==============================================================================
11
16
  // GET single operation
@@ -44,7 +49,7 @@ export function createGetOperationFactory(_ref) {
44
49
  status: 200
45
50
  }]).handler( /*#__PURE__*/function () {
46
51
  var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(req) {
47
- var _yield$getReadParams, mergedParams, scope, rawResult, result;
52
+ var _yield$getReadParams, mergedParams, scope, session, rawResult, result;
48
53
  return _regeneratorRuntime().wrap(function _callee$(_context) {
49
54
  while (1) switch (_context.prev = _context.next) {
50
55
  case 0:
@@ -61,11 +66,12 @@ export function createGetOperationFactory(_ref) {
61
66
  _yield$getReadParams = _context.sent;
62
67
  mergedParams = _yield$getReadParams.params;
63
68
  scope = _yield$getReadParams.scope;
69
+ session = _yield$getReadParams.session;
64
70
  if (!(table && db)) {
65
- _context.next = 12;
71
+ _context.next = 13;
66
72
  break;
67
73
  }
68
- _context.next = 9;
74
+ _context.next = 10;
69
75
  return createAction({
70
76
  bodySchema: schemas.response,
71
77
  db: db,
@@ -75,40 +81,43 @@ export function createGetOperationFactory(_ref) {
75
81
  })(mergedParams, {
76
82
  scope: scope
77
83
  });
78
- case 9:
84
+ case 10:
79
85
  _context.t0 = _context.sent;
80
- _context.next = 13;
86
+ _context.next = 14;
81
87
  break;
82
- case 12:
83
- _context.t0 = mergedParams;
84
88
  case 13:
89
+ _context.t0 = mergedParams;
90
+ case 14:
85
91
  rawResult = _context.t0;
86
92
  result = rawResult !== null && rawResult !== void 0 ? rawResult : {};
87
93
  if (!handler) {
88
- _context.next = 19;
94
+ _context.next = 20;
89
95
  break;
90
96
  }
91
- _context.next = 18;
97
+ _context.next = 19;
92
98
  return handler({
93
99
  data: result,
94
- params: mergedParams,
100
+ // callerId 只给 handler,不进上面那份筛选/写入用的 params(见 getReadParams)。
101
+ params: _objectSpread(_objectSpread({}, mergedParams), {}, {
102
+ callerId: callerIdOf(session)
103
+ }),
95
104
  req: req
96
105
  });
97
- case 18:
98
- result = _context.sent;
99
106
  case 19:
107
+ result = _context.sent;
108
+ case 20:
100
109
  return _context.abrupt("return", TypedNextResponse.json(result, {
101
110
  status: 200
102
111
  }));
103
- case 22:
104
- _context.prev = 22;
112
+ case 23:
113
+ _context.prev = 23;
105
114
  _context.t1 = _context["catch"](0);
106
115
  return _context.abrupt("return", handleOperationError(_context.t1, catchHandler));
107
- case 25:
116
+ case 26:
108
117
  case "end":
109
118
  return _context.stop();
110
119
  }
111
- }, _callee, null, [[0, 22]]);
120
+ }, _callee, null, [[0, 23]]);
112
121
  }));
113
122
  return function (_x) {
114
123
  return _ref4.apply(this, arguments);
@@ -155,7 +164,7 @@ export function createGetListOperationFactory(_ref5) {
155
164
  status: 200
156
165
  }]).handler( /*#__PURE__*/function () {
157
166
  var _ref8 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(req) {
158
- var _yield$getReadParams2, mergedParams, scope, result;
167
+ var _yield$getReadParams2, mergedParams, scope, session, result;
159
168
  return _regeneratorRuntime().wrap(function _callee2$(_context2) {
160
169
  while (1) switch (_context2.prev = _context2.next) {
161
170
  case 0:
@@ -172,11 +181,12 @@ export function createGetListOperationFactory(_ref5) {
172
181
  _yield$getReadParams2 = _context2.sent;
173
182
  mergedParams = _yield$getReadParams2.params;
174
183
  scope = _yield$getReadParams2.scope;
184
+ session = _yield$getReadParams2.session;
175
185
  if (!(table && db)) {
176
- _context2.next = 12;
186
+ _context2.next = 13;
177
187
  break;
178
188
  }
179
- _context2.next = 9;
189
+ _context2.next = 10;
180
190
  return createAction({
181
191
  bodySchema: schemas.response,
182
192
  db: db,
@@ -186,42 +196,45 @@ export function createGetListOperationFactory(_ref5) {
186
196
  })(mergedParams, {
187
197
  scope: scope
188
198
  });
189
- case 9:
199
+ case 10:
190
200
  _context2.t0 = _context2.sent;
191
- _context2.next = 13;
201
+ _context2.next = 14;
192
202
  break;
193
- case 12:
203
+ case 13:
194
204
  _context2.t0 = {
195
205
  data: [],
196
206
  total: 0
197
207
  };
198
- case 13:
208
+ case 14:
199
209
  result = _context2.t0;
200
210
  if (!handler) {
201
- _context2.next = 18;
211
+ _context2.next = 19;
202
212
  break;
203
213
  }
204
- _context2.next = 17;
214
+ _context2.next = 18;
205
215
  return handler({
206
216
  data: result,
207
- params: mergedParams,
217
+ // callerId 只给 handler,不进上面那份筛选/写入用的 params(见 getReadParams)。
218
+ params: _objectSpread(_objectSpread({}, mergedParams), {}, {
219
+ callerId: callerIdOf(session)
220
+ }),
208
221
  req: req
209
222
  });
210
- case 17:
211
- result = _context2.sent;
212
223
  case 18:
224
+ result = _context2.sent;
225
+ case 19:
213
226
  return _context2.abrupt("return", TypedNextResponse.json(result, {
214
227
  status: 200
215
228
  }));
216
- case 21:
217
- _context2.prev = 21;
229
+ case 22:
230
+ _context2.prev = 22;
218
231
  _context2.t1 = _context2["catch"](0);
219
232
  return _context2.abrupt("return", handleOperationError(_context2.t1, catchHandler));
220
- case 24:
233
+ case 25:
221
234
  case "end":
222
235
  return _context2.stop();
223
236
  }
224
- }, _callee2, null, [[0, 21]]);
237
+ }, _callee2, null, [[0, 22]]);
225
238
  }));
226
239
  return function (_x2) {
227
240
  return _ref8.apply(this, arguments);
@@ -5,6 +5,7 @@ import { type RouteOpenApiOperation } from "./open-api-operation.js";
5
5
  import { AccessOptions, ActionFactory, DefaultSession, RouteCatch, SessionGetter } from "./operation-common.js";
6
6
  import { ScopeArg } from "../scope.js";
7
7
  export type PostOperationParams<IB extends ZodSchema> = z.infer<IB> & Record<string, unknown> & {
8
+ callerId?: string;
8
9
  creatorId?: string;
9
10
  };
10
11
  export interface PostOperationOptions<IB extends ZodSchema, OB extends ZodSchema, TTable, TSession = DefaultSession> {
@@ -37,6 +38,7 @@ export declare function createPostOperationFactory<TTable>({ createAction, getTa
37
38
  getSession: SessionGetter<TSession>;
38
39
  }) => <IB extends z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, OB extends z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>({ schemas, access, contentType, openApiOperation, parseBody, setBody, table, handler, catch: catchHandler, }: PostOperationOptions<IB, OB, TTable, TSession>) => import("next-rest-framework").RouteOperationDefinition<"POST">;
39
40
  export type PutOperationParams<IB extends ZodSchema> = z.infer<IB> & Record<string, unknown> & {
41
+ callerId?: string;
40
42
  editorId?: string;
41
43
  };
42
44
  export interface PutOperationOptions<IB extends ZodSchema, OB extends ZodSchema, TTable, TSession = DefaultSession> {
@@ -65,7 +67,7 @@ export declare function createPutOperationFactory<TTable>({ createAction, getTab
65
67
  getSession: SessionGetter<TSession>;
66
68
  }) => <IB extends z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, OB extends z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>({ schemas, access, openApiOperation, table, setBody, handler, catch: catchHandler, }: PutOperationOptions<IB, OB, TTable, TSession>) => import("next-rest-framework").RouteOperationDefinition<"PUT">;
67
69
  export type DeleteOperationParams<B extends ZodSchema> = z.infer<B> & Record<string, unknown> & {
68
- creatorId?: string;
70
+ callerId?: string;
69
71
  id: string;
70
72
  };
71
73
  export interface DeleteOperationOptions<TTable, B extends ZodSchema, TSession = DefaultSession> {
@@ -10,13 +10,17 @@ function _asyncToGenerator(fn) { return function () { var self = this, args = ar
10
10
  import { routeOperation, TypedNextResponse } from "next-rest-framework";
11
11
  import { z } from "zod";
12
12
  import { createOpenApiOperation } from "./open-api-operation.js";
13
- import { getDefaultTags, handleOperationError, readPostBody, resolveAccess, sessionLoader } from "./operation-common.js";
13
+ import { callerIdOf, getDefaultTags, handleOperationError, readPostBody, resolveAccess, sessionLoader } from "./operation-common.js";
14
14
  import { NO_SCOPE } from "../scope.js";
15
15
 
16
16
  // ==============================================================================
17
17
  // POST create operation
18
18
  // ==============================================================================
19
19
 
20
+ // creatorId 是**归属戳**(access.scope 指的那一列)——默认作用域下它确实叫 creatorId,
21
+ // 但换成 `scope: { column: "ownerId" }` 之后这一行盖的就是 ownerId 了。要「谁发的请求」
22
+ // 一律读 callerId,那个四个方法都有、也不受作用域配置影响。
23
+
20
24
  export function createPostOperationFactory(_ref) {
21
25
  var createAction = _ref.createAction,
22
26
  getTableName = _ref.getTableName;
@@ -127,7 +131,11 @@ export function createPostOperationFactory(_ref) {
127
131
  _context.next = 28;
128
132
  return handler({
129
133
  data: raw,
130
- params: params,
134
+ // callerId 只加在**交给 handler 的那一份**上,不进上面 createAction 收到的
135
+ // params —— 那一份会被原样 insert,而 callerId 不是任何表的列。
136
+ params: _objectSpread(_objectSpread({}, params), {}, {
137
+ callerId: callerIdOf(session)
138
+ }),
131
139
  req: req
132
140
  });
133
141
  case 28:
@@ -163,6 +171,9 @@ export function createPostOperationFactory(_ref) {
163
171
  // PUT update operation
164
172
  // ==============================================================================
165
173
 
174
+ // editorId 是要写进行里的**审计列**(「谁改的」)。它恰好等于调用者,但语义是两件事 ——
175
+ // 判权请读 callerId,别读它。
176
+
166
177
  export function createPutOperationFactory(_ref5) {
167
178
  var createAction = _ref5.createAction,
168
179
  getTableName = _ref5.getTableName;
@@ -279,7 +290,11 @@ export function createPutOperationFactory(_ref5) {
279
290
  _context2.next = 39;
280
291
  return handler({
281
292
  data: raw,
282
- params: params,
293
+ // 同 POST:callerId 不进 createAction 那一份(它会被 .set() 原样写进 UPDATE,
294
+ // 而 callerId 不是列)。editorId 是列,所以它留在 params 里。
295
+ params: _objectSpread(_objectSpread({}, params), {}, {
296
+ callerId: editorId
297
+ }),
283
298
  req: req
284
299
  });
285
300
  case 39:
@@ -318,6 +333,11 @@ export function createPutOperationFactory(_ref5) {
318
333
  var defaultDeleteBodySchema = z.object({
319
334
  id: z.string().describe("Id of the row to delete.")
320
335
  });
336
+
337
+ // 原先这里声明的是 `creatorId?: string`,而删除**从来没有填过它** —— 类型说有、运行时没有,
338
+ // 于是 `requireAdmin(params.creatorId)` 这种判权写法编译绿灯、线上对所有人 401。换成 callerId
339
+ // 并且真的盖上。
340
+
321
341
  export function createDeleteOperationFactory(_ref9) {
322
342
  var createAction = _ref9.createAction,
323
343
  getTableName = _ref9.getTableName;
@@ -345,7 +365,7 @@ export function createDeleteOperationFactory(_ref9) {
345
365
  contentType: "application/json"
346
366
  }).handler( /*#__PURE__*/function () {
347
367
  var _ref12 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(req) {
348
- var bodySchema, body, _yield$resolveAccess3, scope, data;
368
+ var bodySchema, body, loadSession, _yield$resolveAccess3, scope, data;
349
369
  return _regeneratorRuntime().wrap(function _callee3$(_context3) {
350
370
  while (1) switch (_context3.prev = _context3.next) {
351
371
  case 0:
@@ -357,20 +377,22 @@ export function createDeleteOperationFactory(_ref9) {
357
377
  case 5:
358
378
  _context3.t1 = _context3.sent;
359
379
  body = _context3.t0.parse.call(_context3.t0, _context3.t1);
360
- _context3.next = 9;
380
+ // loadSession 带缓存,下面取 callerId 时不会再往返一次。
381
+ loadSession = sessionLoader(getSession, req);
382
+ _context3.next = 10;
361
383
  return resolveAccess({
362
384
  access: access,
363
- loadSession: sessionLoader(getSession, req),
385
+ loadSession: loadSession,
364
386
  method: "DELETE"
365
387
  });
366
- case 9:
388
+ case 10:
367
389
  _yield$resolveAccess3 = _context3.sent;
368
390
  scope = _yield$resolveAccess3.scope;
369
391
  if (!(table && db)) {
370
- _context3.next = 17;
392
+ _context3.next = 18;
371
393
  break;
372
394
  }
373
- _context3.next = 14;
395
+ _context3.next = 15;
374
396
  return createAction({
375
397
  db: db,
376
398
  table: table
@@ -379,33 +401,54 @@ export function createDeleteOperationFactory(_ref9) {
379
401
  }, {
380
402
  scope: scope
381
403
  });
382
- case 14:
404
+ case 15:
383
405
  _context3.t2 = _context3.sent;
384
- _context3.next = 18;
406
+ _context3.next = 19;
385
407
  break;
386
- case 17:
387
- _context3.t2 = body;
388
408
  case 18:
409
+ _context3.t2 = body;
410
+ case 19:
389
411
  data = _context3.t2;
390
- _context3.next = 21;
391
- return handler === null || handler === void 0 ? void 0 : handler({
392
- data: data,
393
- params: body,
394
- req: req
395
- });
396
- case 21:
412
+ if (!handler) {
413
+ _context3.next = 37;
414
+ break;
415
+ }
416
+ _context3.t3 = handler;
417
+ _context3.t4 = data;
418
+ _context3.t5 = _objectSpread;
419
+ _context3.t6 = _objectSpread({}, body);
420
+ _context3.t7 = {};
421
+ _context3.t8 = callerIdOf;
422
+ _context3.next = 29;
423
+ return loadSession();
424
+ case 29:
425
+ _context3.t9 = _context3.sent;
426
+ _context3.t10 = (0, _context3.t8)(_context3.t9);
427
+ _context3.t11 = {
428
+ callerId: _context3.t10
429
+ };
430
+ _context3.t12 = (0, _context3.t5)(_context3.t6, _context3.t7, _context3.t11);
431
+ _context3.t13 = req;
432
+ _context3.t14 = {
433
+ data: _context3.t4,
434
+ params: _context3.t12,
435
+ req: _context3.t13
436
+ };
437
+ _context3.next = 37;
438
+ return (0, _context3.t3)(_context3.t14);
439
+ case 37:
397
440
  return _context3.abrupt("return", TypedNextResponse.json(data, {
398
441
  status: 200
399
442
  }));
400
- case 24:
401
- _context3.prev = 24;
402
- _context3.t3 = _context3["catch"](0);
403
- return _context3.abrupt("return", handleOperationError(_context3.t3, catchHandler));
404
- case 27:
443
+ case 40:
444
+ _context3.prev = 40;
445
+ _context3.t15 = _context3["catch"](0);
446
+ return _context3.abrupt("return", handleOperationError(_context3.t15, catchHandler));
447
+ case 43:
405
448
  case "end":
406
449
  return _context3.stop();
407
450
  }
408
- }, _callee3, null, [[0, 24]]);
451
+ }, _callee3, null, [[0, 40]]);
409
452
  }));
410
453
  return function (_x3) {
411
454
  return _ref12.apply(this, arguments);
@@ -8,6 +8,18 @@ export type RouteCatch = (error: Error) => Promise<JsonResponse | undefined>;
8
8
  export interface DefaultSession {
9
9
  userId?: string;
10
10
  }
11
+ /**
12
+ * 「这次请求是谁发的」。四个方法都会把它盖进 params.callerId,自定义 handler 判权、署名、
13
+ * 判「是不是本人」一律读它。
14
+ *
15
+ * **不要拿 params.creatorId 当调用者用。** 那是另一件事:POST 上的 creatorId 是**归属戳**
16
+ * (access.scope 指的那一列,换成 ownerId 时它就不叫 creatorId 了),PUT 上的 editorId 是要
17
+ * 写进行里的**审计列**。两者都恰好等于调用者只是默认配置下的巧合。
18
+ *
19
+ * 会话形状是泛型的(调用方可以塞自己的 Scope 进来),所以这里按 DefaultSession 取 userId ——
20
+ * 自定义会话只要带着这个字段就通用。
21
+ */
22
+ export declare function callerIdOf(session: unknown): string | undefined;
11
23
  /**
12
24
  * 会话读取器。泛型化是为了让调用方能在这里一次性解析出「你是谁 + 你现在站在哪个空间 +
13
25
  * 你在那个空间里是什么角色」,后面 access.scope / access.can 都读同一份,不必各自再查一遍库。
@@ -99,7 +111,7 @@ export declare function getDefaultTags<TTable>({ getTableName, table, }: {
99
111
  table?: TTable;
100
112
  }): string[];
101
113
  export type GetOperationParams<Q extends ZodSchema> = z.infer<Q> & Record<string, unknown> & {
102
- creatorId?: string;
114
+ callerId?: string;
103
115
  };
104
116
  /**
105
117
  * 读操作的参数与作用域。
@@ -19,6 +19,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  // src/backend/route-operation/operation-common.ts
20
20
  var operation_common_exports = {};
21
21
  __export(operation_common_exports, {
22
+ callerIdOf: () => callerIdOf,
22
23
  getDefaultTags: () => getDefaultTags,
23
24
  getReadParams: () => getReadParams,
24
25
  handleOperationError: () => handleOperationError,
@@ -30,6 +31,9 @@ module.exports = __toCommonJS(operation_common_exports);
30
31
  var import_next_rest_framework = require("next-rest-framework");
31
32
  var import_errors = require("../errors");
32
33
  var import_scope = require("../scope");
34
+ function callerIdOf(session) {
35
+ return session == null ? void 0 : session.userId;
36
+ }
33
37
  var DEFAULT_SCOPE_COLUMN = "creatorId";
34
38
  function sessionLoader(getSession, req) {
35
39
  let pending;
@@ -124,6 +128,9 @@ async function getReadParams({
124
128
  Object.fromEntries(new URL(req.url).searchParams)
125
129
  );
126
130
  return {
131
+ // 这一份**不带 callerId**:它会被当成筛选条件送进查询构造器,而 callerId 不是任何表的列。
132
+ // 列表那边认不出的键会跳过(get-list-query 的 `if (!targetColumn) continue`),但别指望
133
+ // 这条兜底 —— 交给 handler 的那一份在 read-operation-core 里单独拼,见那里。
127
134
  params: { ...queryParams, ...extraParams },
128
135
  scope,
129
136
  session
@@ -131,6 +138,7 @@ async function getReadParams({
131
138
  }
132
139
  // Annotate the CommonJS export names for ESM import in node:
133
140
  0 && (module.exports = {
141
+ callerIdOf,
134
142
  getDefaultTags,
135
143
  getReadParams,
136
144
  handleOperationError,
@@ -60,7 +60,11 @@ function createGetOperationFactory({
60
60
  }
61
61
  ]).handler(async (req) => {
62
62
  try {
63
- const { params: mergedParams, scope } = await (0, import_operation_common.getReadParams)({
63
+ const {
64
+ params: mergedParams,
65
+ scope,
66
+ session
67
+ } = await (0, import_operation_common.getReadParams)({
64
68
  access,
65
69
  getSession,
66
70
  req,
@@ -78,7 +82,8 @@ function createGetOperationFactory({
78
82
  if (handler) {
79
83
  result = await handler({
80
84
  data: result,
81
- params: mergedParams,
85
+ // callerId 只给 handler,不进上面那份筛选/写入用的 params(见 getReadParams)。
86
+ params: { ...mergedParams, callerId: (0, import_operation_common.callerIdOf)(session) },
82
87
  req
83
88
  });
84
89
  }
@@ -121,7 +126,11 @@ function createGetListOperationFactory({
121
126
  }
122
127
  ]).handler(async (req) => {
123
128
  try {
124
- const { params: mergedParams, scope } = await (0, import_operation_common.getReadParams)({
129
+ const {
130
+ params: mergedParams,
131
+ scope,
132
+ session
133
+ } = await (0, import_operation_common.getReadParams)({
125
134
  access,
126
135
  getSession,
127
136
  req,
@@ -138,7 +147,8 @@ function createGetListOperationFactory({
138
147
  if (handler) {
139
148
  result = await handler({
140
149
  data: result,
141
- params: mergedParams,
150
+ // callerId 只给 handler,不进上面那份筛选/写入用的 params(见 getReadParams)。
151
+ params: { ...mergedParams, callerId: (0, import_operation_common.callerIdOf)(session) },
142
152
  req
143
153
  });
144
154
  }
@@ -5,6 +5,7 @@ import { type RouteOpenApiOperation } from "./open-api-operation.js";
5
5
  import { AccessOptions, ActionFactory, DefaultSession, RouteCatch, SessionGetter } from "./operation-common.js";
6
6
  import { ScopeArg } from "../scope.js";
7
7
  export type PostOperationParams<IB extends ZodSchema> = z.infer<IB> & Record<string, unknown> & {
8
+ callerId?: string;
8
9
  creatorId?: string;
9
10
  };
10
11
  export interface PostOperationOptions<IB extends ZodSchema, OB extends ZodSchema, TTable, TSession = DefaultSession> {
@@ -37,6 +38,7 @@ export declare function createPostOperationFactory<TTable>({ createAction, getTa
37
38
  getSession: SessionGetter<TSession>;
38
39
  }) => <IB extends z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, OB extends z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>({ schemas, access, contentType, openApiOperation, parseBody, setBody, table, handler, catch: catchHandler, }: PostOperationOptions<IB, OB, TTable, TSession>) => import("next-rest-framework").RouteOperationDefinition<"POST">;
39
40
  export type PutOperationParams<IB extends ZodSchema> = z.infer<IB> & Record<string, unknown> & {
41
+ callerId?: string;
40
42
  editorId?: string;
41
43
  };
42
44
  export interface PutOperationOptions<IB extends ZodSchema, OB extends ZodSchema, TTable, TSession = DefaultSession> {
@@ -65,7 +67,7 @@ export declare function createPutOperationFactory<TTable>({ createAction, getTab
65
67
  getSession: SessionGetter<TSession>;
66
68
  }) => <IB extends z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, OB extends z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>({ schemas, access, openApiOperation, table, setBody, handler, catch: catchHandler, }: PutOperationOptions<IB, OB, TTable, TSession>) => import("next-rest-framework").RouteOperationDefinition<"PUT">;
67
69
  export type DeleteOperationParams<B extends ZodSchema> = z.infer<B> & Record<string, unknown> & {
68
- creatorId?: string;
70
+ callerId?: string;
69
71
  id: string;
70
72
  };
71
73
  export interface DeleteOperationOptions<TTable, B extends ZodSchema, TSession = DefaultSession> {
@@ -85,7 +85,12 @@ function createPostOperationFactory({
85
85
  })(params))[0] : params;
86
86
  const data = handler ? await handler({
87
87
  data: raw,
88
- params,
88
+ // callerId 只加在**交给 handler 的那一份**上,不进上面 createAction 收到的
89
+ // params —— 那一份会被原样 insert,而 callerId 不是任何表的列。
90
+ params: {
91
+ ...params,
92
+ callerId: (0, import_operation_common.callerIdOf)(session)
93
+ },
89
94
  req
90
95
  }) : raw;
91
96
  return import_next_rest_framework.TypedNextResponse.json(data, { status: 200 });
@@ -146,7 +151,12 @@ function createPutOperationFactory({
146
151
  })(params, { scope }) : params;
147
152
  const data = handler ? await handler({
148
153
  data: raw,
149
- params,
154
+ // 同 POST:callerId 不进 createAction 那一份(它会被 .set() 原样写进 UPDATE,
155
+ // 而 callerId 不是列)。editorId 是列,所以它留在 params 里。
156
+ params: {
157
+ ...params,
158
+ callerId: editorId
159
+ },
150
160
  req
151
161
  }) : raw;
152
162
  return import_next_rest_framework.TypedNextResponse.json(data, { status: 200 });
@@ -187,13 +197,23 @@ function createDeleteOperationFactory({
187
197
  const body = bodySchema.parse(
188
198
  await req.json()
189
199
  );
200
+ const loadSession = (0, import_operation_common.sessionLoader)(getSession, req);
190
201
  const { scope } = await (0, import_operation_common.resolveAccess)({
191
202
  access,
192
- loadSession: (0, import_operation_common.sessionLoader)(getSession, req),
203
+ loadSession,
193
204
  method: "DELETE"
194
205
  });
195
206
  const data = table && db ? await createAction({ db, table })({ id: body.id }, { scope }) : body;
196
- await (handler == null ? void 0 : handler({ data, params: body, req }));
207
+ if (handler) {
208
+ await handler({
209
+ data,
210
+ params: {
211
+ ...body,
212
+ callerId: (0, import_operation_common.callerIdOf)(await loadSession())
213
+ },
214
+ req
215
+ });
216
+ }
197
217
  return import_next_rest_framework.TypedNextResponse.json(data, { status: 200 });
198
218
  } catch (error) {
199
219
  return (0, import_operation_common.handleOperationError)(error, catchHandler);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai0x0/utils",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "AI0x0 utils",
5
5
  "keywords": [
6
6
  "ai0x0"