@terreno/api 0.13.1 → 0.13.2

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/api.js CHANGED
@@ -335,6 +335,9 @@ function _buildModelRouter(model, options) {
335
335
  body = (0, transformers_1.transform)(options, req.body, "create", req.user);
336
336
  }
337
337
  catch (error) {
338
+ if ((0, errors_1.isAPIError)(error)) {
339
+ throw error;
340
+ }
338
341
  throw new errors_1.APIError({
339
342
  disableExternalErrorTracking: (0, errors_1.getDisableExternalErrorTracking)(error),
340
343
  error: error,
@@ -687,6 +690,9 @@ function _buildModelRouter(model, options) {
687
690
  body = (0, transformers_1.transform)(options, req.body, "update", req.user);
688
691
  }
689
692
  catch (error) {
693
+ if ((0, errors_1.isAPIError)(error)) {
694
+ throw error;
695
+ }
690
696
  throw new errors_1.APIError({
691
697
  disableExternalErrorTracking: (0, errors_1.getDisableExternalErrorTracking)(error),
692
698
  error: error,
@@ -968,6 +974,9 @@ function _buildModelRouter(model, options) {
968
974
  body = (0, transformers_1.transform)(options, body, "update", req.user);
969
975
  }
970
976
  catch (error) {
977
+ if ((0, errors_1.isAPIError)(error)) {
978
+ throw error;
979
+ }
971
980
  throw new errors_1.APIError({
972
981
  disableExternalErrorTracking: (0, errors_1.getDisableExternalErrorTracking)(error),
973
982
  error: error,
package/dist/api.test.js CHANGED
@@ -774,7 +774,7 @@ var transformers_1 = require("./transformers");
774
774
  }),
775
775
  }));
776
776
  server = (0, supertest_1.default)(app);
777
- return [4 /*yield*/, server.post("/food").send({ calories: 15, name: "Broccoli" }).expect(400)];
777
+ return [4 /*yield*/, server.post("/food").send({ calories: 15, name: "Broccoli" }).expect(403)];
778
778
  case 1:
779
779
  res = _a.sent();
780
780
  (0, bun_test_1.expect)(res.body.title).toContain("cannot write fields");
@@ -1699,7 +1699,7 @@ var transformers_1 = require("./transformers");
1699
1699
  }),
1700
1700
  }));
1701
1701
  server = (0, supertest_1.default)(app);
1702
- return [4 /*yield*/, server.post("/food").send({ calories: 15, name: "Broccoli" }).expect(400)];
1702
+ return [4 /*yield*/, server.post("/food").send({ calories: 15, name: "Broccoli" }).expect(403)];
1703
1703
  case 1:
1704
1704
  res = _a.sent();
1705
1705
  (0, bun_test_1.expect)(res.body.title).toContain("cannot write fields");
@@ -12,6 +12,6 @@ export interface VersionConfigDocument extends mongoose.Document {
12
12
  updated?: Date;
13
13
  }
14
14
  export interface VersionConfigModel extends mongoose.Model<VersionConfigDocument> {
15
- findOneOrNone(query: Record<string, any>, errorArgs?: Partial<APIErrorConstructor>): Promise<(Document & VersionConfigDocument) | null>;
15
+ findOneOrNone(query: Record<string, unknown>, errorArgs?: Partial<APIErrorConstructor>): Promise<(Document & VersionConfigDocument) | null>;
16
16
  }
17
17
  export declare const VersionConfig: VersionConfigModel;
@@ -6,7 +6,7 @@ export interface TerrenoTransformer<T> {
6
6
  transform?: (obj: Partial<T>, method: "create" | "update", user?: User) => Partial<T> | undefined;
7
7
  serialize?: (obj: T, user?: User) => Partial<T> | undefined;
8
8
  }
9
- export declare function AdminOwnerTransformer<T>(options: {
9
+ export declare const AdminOwnerTransformer: <T>(options: {
10
10
  anonReadFields?: string[];
11
11
  authReadFields?: string[];
12
12
  ownerReadFields?: string[];
@@ -15,11 +15,11 @@ export declare function AdminOwnerTransformer<T>(options: {
15
15
  authWriteFields?: string[];
16
16
  ownerWriteFields?: string[];
17
17
  adminWriteFields?: string[];
18
- }): TerrenoTransformer<T>;
19
- export declare function transform<T>(options: ModelRouterOptions<T>, data: Partial<T> | Partial<T>[], method: "create" | "update", user?: User): Partial<T> | (Partial<T> | undefined)[] | undefined;
20
- export declare function serialize<T>(req: express.Request, options: ModelRouterOptions<T>, data: (Document<any, any, any> & T) | (Document<any, any, any> & T)[]): Partial<T> | (Partial<T> | undefined)[] | undefined;
18
+ }) => TerrenoTransformer<T>;
19
+ export declare const transform: <T>(options: ModelRouterOptions<T>, data: Partial<T> | Partial<T>[], method: "create" | "update", user?: User) => Partial<T> | (Partial<T> | undefined)[] | undefined;
20
+ export declare const serialize: <T>(req: express.Request, options: ModelRouterOptions<T>, data: (Document & T) | (Document & T)[]) => Partial<T> | (Partial<T> | undefined)[] | undefined;
21
21
  /**
22
22
  * Default response handler for modelRouter. Calls toObject on each doc and returns the result,
23
23
  * using transformers.serializer if provided.
24
24
  */
25
- export declare function defaultResponseHandler<T>(doc: (Document<any, any, any> & T) | (Document<any, any, any> & T)[] | null, method: "list" | "create" | "read" | "update", request: express.Request, options: ModelRouterOptions<T>): Promise<Partial<T> | (Partial<T> | undefined)[] | null | undefined>;
25
+ export declare const defaultResponseHandler: <T>(doc: (Document & T) | (Document & T)[] | null, method: "list" | "create" | "read" | "update", request: express.Request, options: ModelRouterOptions<T>) => Promise<Partial<T> | (Partial<T> | undefined)[] | null | undefined>;
@@ -72,13 +72,10 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
72
72
  return to.concat(ar || Array.prototype.slice.call(from));
73
73
  };
74
74
  Object.defineProperty(exports, "__esModule", { value: true });
75
- exports.AdminOwnerTransformer = AdminOwnerTransformer;
76
- exports.transform = transform;
77
- exports.serialize = serialize;
78
- exports.defaultResponseHandler = defaultResponseHandler;
75
+ exports.defaultResponseHandler = exports.serialize = exports.transform = exports.AdminOwnerTransformer = void 0;
79
76
  var errors_1 = require("./errors");
80
77
  var logger_1 = require("./logger");
81
- function getUserType(user, obj) {
78
+ var getUserType = function (user, obj) {
82
79
  if (user === null || user === void 0 ? void 0 : user.admin) {
83
80
  return "admin";
84
81
  }
@@ -89,9 +86,9 @@ function getUserType(user, obj) {
89
86
  return "auth";
90
87
  }
91
88
  return "anon";
92
- }
93
- function AdminOwnerTransformer(options) {
94
- function pickFields(obj, fields) {
89
+ };
90
+ var AdminOwnerTransformer = function (options) {
91
+ var pickFields = function (obj, fields) {
95
92
  var e_1, _a;
96
93
  var newData = {};
97
94
  try {
@@ -110,7 +107,7 @@ function AdminOwnerTransformer(options) {
110
107
  finally { if (e_1) throw e_1.error; }
111
108
  }
112
109
  return newData;
113
- }
110
+ };
114
111
  return {
115
112
  serialize: function (obj, user) {
116
113
  var _a, _b, _c, _d;
@@ -126,7 +123,6 @@ function AdminOwnerTransformer(options) {
126
123
  }
127
124
  return pickFields(obj, __spreadArray(__spreadArray([], __read(((_d = options.anonReadFields) !== null && _d !== void 0 ? _d : [])), false), ["id"], false));
128
125
  },
129
- // TODO: Migrate AdminOwnerTransform to use pre-hooks.
130
126
  transform: function (obj, _method, user) {
131
127
  var _a, _b, _c, _d;
132
128
  var userType = getUserType(user, obj);
@@ -145,13 +141,17 @@ function AdminOwnerTransformer(options) {
145
141
  }
146
142
  var unallowedFields = Object.keys(obj).filter(function (k) { return !allowedFields.includes(k); });
147
143
  if (unallowedFields.length) {
148
- throw new Error("User of type ".concat(userType, " cannot write fields: ").concat(unallowedFields.join(", ")));
144
+ throw new errors_1.APIError({
145
+ status: 403,
146
+ title: "User of type ".concat(userType, " cannot write fields: ").concat(unallowedFields.join(", ")),
147
+ });
149
148
  }
150
149
  return obj;
151
150
  },
152
151
  };
153
- }
154
- function transform(options, data, method, user) {
152
+ };
153
+ exports.AdminOwnerTransformer = AdminOwnerTransformer;
154
+ var transform = function (options, data, method, user) {
155
155
  var _a, _b;
156
156
  if (!((_a = options.transformer) === null || _a === void 0 ? void 0 : _a.transform)) {
157
157
  return data;
@@ -163,8 +163,9 @@ function transform(options, data, method, user) {
163
163
  return transformFn(data, method, user);
164
164
  }
165
165
  return data.map(function (d) { return transformFn(d, method, user); });
166
- }
167
- function serialize(req, options, data) {
166
+ };
167
+ exports.transform = transform;
168
+ var serialize = function (req, options, data) {
168
169
  var _a;
169
170
  var serializeFn = function (serializeData, serializeUser) {
170
171
  var _a, _b;
@@ -190,30 +191,30 @@ function serialize(req, options, data) {
190
191
  return serializeFn(data, req.user);
191
192
  }
192
193
  return data.map(function (d) { return serializeFn(d, req.user); });
193
- }
194
+ };
195
+ exports.serialize = serialize;
194
196
  /**
195
197
  * Default response handler for modelRouter. Calls toObject on each doc and returns the result,
196
198
  * using transformers.serializer if provided.
197
199
  */
198
- function defaultResponseHandler(doc, method, request, options) {
199
- return __awaiter(this, void 0, void 0, function () {
200
- var errorObj;
201
- return __generator(this, function (_a) {
202
- if (!doc) {
203
- return [2 /*return*/, null];
204
- }
205
- try {
206
- return [2 /*return*/, serialize(request, options, doc)];
207
- }
208
- catch (error) {
209
- errorObj = error;
210
- throw new errors_1.APIError({
211
- error: errorObj,
212
- status: 400,
213
- title: "Error serializing ".concat(method, " response: ").concat(errorObj.message),
214
- });
215
- }
216
- return [2 /*return*/];
217
- });
200
+ var defaultResponseHandler = function (doc, method, request, options) { return __awaiter(void 0, void 0, void 0, function () {
201
+ var errorObj;
202
+ return __generator(this, function (_a) {
203
+ if (!doc) {
204
+ return [2 /*return*/, null];
205
+ }
206
+ try {
207
+ return [2 /*return*/, (0, exports.serialize)(request, options, doc)];
208
+ }
209
+ catch (error) {
210
+ errorObj = error;
211
+ throw new errors_1.APIError({
212
+ error: errorObj,
213
+ status: 400,
214
+ title: "Error serializing ".concat(method, " response: ").concat(errorObj.message),
215
+ });
216
+ }
217
+ return [2 /*return*/];
218
218
  });
219
- }
219
+ }); };
220
+ exports.defaultResponseHandler = defaultResponseHandler;
package/package.json CHANGED
@@ -104,5 +104,5 @@
104
104
  "updateSnapshot": "bun test --update-snapshots"
105
105
  },
106
106
  "types": "dist/index.d.ts",
107
- "version": "0.13.1"
107
+ "version": "0.13.2"
108
108
  }
package/src/api.test.ts CHANGED
@@ -576,7 +576,7 @@ describe("@terreno/api", () => {
576
576
  );
577
577
  server = supertest(app);
578
578
 
579
- const res = await server.post("/food").send({calories: 15, name: "Broccoli"}).expect(400);
579
+ const res = await server.post("/food").send({calories: 15, name: "Broccoli"}).expect(403);
580
580
  expect(res.body.title).toContain("cannot write fields");
581
581
  });
582
582
 
@@ -1324,7 +1324,7 @@ describe("@terreno/api", () => {
1324
1324
  );
1325
1325
  server = supertest(app);
1326
1326
 
1327
- const res = await server.post("/food").send({calories: 15, name: "Broccoli"}).expect(400);
1327
+ const res = await server.post("/food").send({calories: 15, name: "Broccoli"}).expect(403);
1328
1328
  expect(res.body.title).toContain("cannot write fields");
1329
1329
  });
1330
1330
 
package/src/api.ts CHANGED
@@ -528,6 +528,9 @@ function _buildModelRouter<T>(model: Model<T>, options: ModelRouterOptions<T>):
528
528
  try {
529
529
  body = transform<T>(options, req.body, "create", req.user);
530
530
  } catch (error: any) {
531
+ if (isAPIError(error)) {
532
+ throw error;
533
+ }
531
534
  throw new APIError({
532
535
  disableExternalErrorTracking: getDisableExternalErrorTracking(error),
533
536
  error,
@@ -827,6 +830,9 @@ function _buildModelRouter<T>(model: Model<T>, options: ModelRouterOptions<T>):
827
830
  try {
828
831
  body = transform<T>(options, req.body, "update", req.user);
829
832
  } catch (error: any) {
833
+ if (isAPIError(error)) {
834
+ throw error;
835
+ }
830
836
  throw new APIError({
831
837
  disableExternalErrorTracking: getDisableExternalErrorTracking(error),
832
838
  error,
@@ -1080,6 +1086,9 @@ function _buildModelRouter<T>(model: Model<T>, options: ModelRouterOptions<T>):
1080
1086
  try {
1081
1087
  body = transform<T>(options, body, "update", req.user) as Partial<T>;
1082
1088
  } catch (error: any) {
1089
+ if (isAPIError(error)) {
1090
+ throw error;
1091
+ }
1083
1092
  throw new APIError({
1084
1093
  disableExternalErrorTracking: getDisableExternalErrorTracking(error),
1085
1094
  error,
@@ -17,7 +17,7 @@ export interface VersionConfigDocument extends mongoose.Document {
17
17
 
18
18
  export interface VersionConfigModel extends mongoose.Model<VersionConfigDocument> {
19
19
  findOneOrNone(
20
- query: Record<string, any>,
20
+ query: Record<string, unknown>,
21
21
  errorArgs?: Partial<APIErrorConstructor>
22
22
  ): Promise<(Document & VersionConfigDocument) | null>;
23
23
  }
@@ -14,7 +14,7 @@ export const openApiEtagMiddleware = (req: Request, res: Response, next: NextFun
14
14
 
15
15
  const originalJson = res.json.bind(res);
16
16
 
17
- res.json = (body: any) => {
17
+ res.json = (body: unknown) => {
18
18
  const jsonString = JSON.stringify(body);
19
19
  const etag = `"${crypto.createHash("sha256").update(jsonString).digest("hex").substring(0, 16)}"`;
20
20
 
@@ -15,7 +15,10 @@ export interface TerrenoTransformer<T> {
15
15
  serialize?: (obj: T, user?: User) => Partial<T> | undefined;
16
16
  }
17
17
 
18
- function getUserType(user?: User, obj?: any): "anon" | "auth" | "owner" | "admin" {
18
+ const getUserType = (
19
+ user?: User,
20
+ obj?: Record<string, unknown>
21
+ ): "anon" | "auth" | "owner" | "admin" => {
19
22
  if (user?.admin) {
20
23
  return "admin";
21
24
  }
@@ -26,10 +29,9 @@ function getUserType(user?: User, obj?: any): "anon" | "auth" | "owner" | "admin
26
29
  return "auth";
27
30
  }
28
31
  return "anon";
29
- }
32
+ };
30
33
 
31
- export function AdminOwnerTransformer<T>(options: {
32
- // TODO: do something with KeyOf here.
34
+ export const AdminOwnerTransformer = <T>(options: {
33
35
  anonReadFields?: string[];
34
36
  authReadFields?: string[];
35
37
  ownerReadFields?: string[];
@@ -38,20 +40,20 @@ export function AdminOwnerTransformer<T>(options: {
38
40
  authWriteFields?: string[];
39
41
  ownerWriteFields?: string[];
40
42
  adminWriteFields?: string[];
41
- }): TerrenoTransformer<T> {
42
- function pickFields(obj: Partial<T>, fields: any[]): Partial<T> {
43
+ }): TerrenoTransformer<T> => {
44
+ const pickFields = (obj: Partial<T>, fields: string[]): Partial<T> => {
43
45
  const newData: Partial<T> = {};
44
46
  for (const field of fields) {
45
- if (obj[field] !== undefined) {
46
- newData[field] = obj[field];
47
+ if ((obj as Record<string, unknown>)[field] !== undefined) {
48
+ (newData as Record<string, unknown>)[field] = (obj as Record<string, unknown>)[field];
47
49
  }
48
50
  }
49
51
  return newData;
50
- }
52
+ };
51
53
 
52
54
  return {
53
55
  serialize: (obj: T, user?: User) => {
54
- const userType = getUserType(user, obj);
56
+ const userType = getUserType(user, obj as Record<string, unknown>);
55
57
  if (userType === "admin") {
56
58
  return pickFields(obj, [...(options.adminReadFields ?? []), "id"]);
57
59
  }
@@ -63,10 +65,9 @@ export function AdminOwnerTransformer<T>(options: {
63
65
  }
64
66
  return pickFields(obj, [...(options.anonReadFields ?? []), "id"]);
65
67
  },
66
- // TODO: Migrate AdminOwnerTransform to use pre-hooks.
67
68
  transform: (obj: Partial<T>, _method: "create" | "update", user?: User) => {
68
- const userType = getUserType(user, obj);
69
- let allowedFields: any;
69
+ const userType = getUserType(user, obj as Record<string, unknown>);
70
+ let allowedFields: string[];
70
71
  if (userType === "admin") {
71
72
  allowedFields = options.adminWriteFields ?? [];
72
73
  } else if (userType === "owner") {
@@ -78,21 +79,22 @@ export function AdminOwnerTransformer<T>(options: {
78
79
  }
79
80
  const unallowedFields = Object.keys(obj).filter((k) => !allowedFields.includes(k));
80
81
  if (unallowedFields.length) {
81
- throw new Error(
82
- `User of type ${userType} cannot write fields: ${unallowedFields.join(", ")}`
83
- );
82
+ throw new APIError({
83
+ status: 403,
84
+ title: `User of type ${userType} cannot write fields: ${unallowedFields.join(", ")}`,
85
+ });
84
86
  }
85
87
  return obj;
86
88
  },
87
89
  };
88
- }
90
+ };
89
91
 
90
- export function transform<T>(
92
+ export const transform = <T>(
91
93
  options: ModelRouterOptions<T>,
92
94
  data: Partial<T> | Partial<T>[],
93
95
  method: "create" | "update",
94
96
  user?: User
95
- ) {
97
+ ) => {
96
98
  if (!options.transformer?.transform) {
97
99
  return data;
98
100
  }
@@ -108,16 +110,16 @@ export function transform<T>(
108
110
  return transformFn(data, method, user);
109
111
  }
110
112
  return data.map((d) => transformFn(d, method, user));
111
- }
113
+ };
112
114
 
113
- export function serialize<T>(
115
+ export const serialize = <T>(
114
116
  req: express.Request,
115
117
  options: ModelRouterOptions<T>,
116
- data: (Document<any, any, any> & T) | (Document<any, any, any> & T)[]
117
- ) {
118
- const serializeFn = (serializeData: Document<any, any, any> & T, serializeUser?: User) => {
118
+ data: (Document & T) | (Document & T)[]
119
+ ) => {
120
+ const serializeFn = (serializeData: Document & T, serializeUser?: User) => {
119
121
  const dataObject = serializeData.toObject() as T;
120
- (dataObject as any).id = serializeData._id;
122
+ (dataObject as Record<string, unknown>).id = serializeData._id;
121
123
 
122
124
  // Search for any value that is a Map and transform it to a plain object.
123
125
  // Otherwise Express drops the contents.
@@ -143,18 +145,18 @@ export function serialize<T>(
143
145
  return serializeFn(data, req.user);
144
146
  }
145
147
  return data.map((d) => serializeFn(d, req.user));
146
- }
148
+ };
147
149
 
148
150
  /**
149
151
  * Default response handler for modelRouter. Calls toObject on each doc and returns the result,
150
152
  * using transformers.serializer if provided.
151
153
  */
152
- export async function defaultResponseHandler<T>(
153
- doc: (Document<any, any, any> & T) | (Document<any, any, any> & T)[] | null,
154
+ export const defaultResponseHandler = async <T>(
155
+ doc: (Document & T) | (Document & T)[] | null,
154
156
  method: "list" | "create" | "read" | "update",
155
157
  request: express.Request,
156
158
  options: ModelRouterOptions<T>
157
- ) {
159
+ ) => {
158
160
  if (!doc) {
159
161
  return null;
160
162
  }
@@ -168,4 +170,4 @@ export async function defaultResponseHandler<T>(
168
170
  title: `Error serializing ${method} response: ${errorObj.message}`,
169
171
  });
170
172
  }
171
- }
173
+ };