@teamkeel/functions-runtime 0.411.0 → 0.412.0-next.1
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.mts +340 -0
- package/dist/index.d.ts +340 -0
- package/dist/index.js +3093 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3097 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +23 -5
- package/.env.test +0 -2
- package/compose.yaml +0 -10
- package/src/Duration.js +0 -40
- package/src/Duration.test.js +0 -34
- package/src/File.js +0 -295
- package/src/ModelAPI.js +0 -377
- package/src/ModelAPI.test.js +0 -1428
- package/src/QueryBuilder.js +0 -184
- package/src/QueryContext.js +0 -90
- package/src/RequestHeaders.js +0 -21
- package/src/TimePeriod.js +0 -89
- package/src/TimePeriod.test.js +0 -148
- package/src/applyAdditionalQueryConstraints.js +0 -22
- package/src/applyJoins.js +0 -67
- package/src/applyWhereConditions.js +0 -124
- package/src/auditing.js +0 -110
- package/src/auditing.test.js +0 -330
- package/src/camelCasePlugin.js +0 -52
- package/src/casing.js +0 -54
- package/src/casing.test.js +0 -56
- package/src/consts.js +0 -14
- package/src/database.js +0 -244
- package/src/errors.js +0 -160
- package/src/handleJob.js +0 -110
- package/src/handleJob.test.js +0 -270
- package/src/handleRequest.js +0 -153
- package/src/handleRequest.test.js +0 -463
- package/src/handleRoute.js +0 -112
- package/src/handleSubscriber.js +0 -105
- package/src/index.d.ts +0 -317
- package/src/index.js +0 -38
- package/src/parsing.js +0 -113
- package/src/parsing.test.js +0 -140
- package/src/permissions.js +0 -77
- package/src/permissions.test.js +0 -118
- package/src/tracing.js +0 -184
- package/src/tracing.test.js +0 -147
- package/src/tryExecuteFunction.js +0 -91
- package/src/tryExecuteJob.js +0 -29
- package/src/tryExecuteSubscriber.js +0 -17
- package/src/type-utils.js +0 -18
- package/vite.config.js +0 -7
|
@@ -1,463 +0,0 @@
|
|
|
1
|
-
import { createJSONRPCRequest, JSONRPCErrorCode } from "json-rpc-2.0";
|
|
2
|
-
import { sql } from "kysely";
|
|
3
|
-
import { handleRequest, RuntimeErrors } from "./handleRequest";
|
|
4
|
-
import { test, expect, beforeEach, describe } from "vitest";
|
|
5
|
-
import { ModelAPI } from "./ModelAPI";
|
|
6
|
-
import { useDatabase } from "./database";
|
|
7
|
-
const { Permissions } = require("./permissions");
|
|
8
|
-
import { PROTO_ACTION_TYPES } from "./consts";
|
|
9
|
-
import KSUID from "ksuid";
|
|
10
|
-
import { ErrorPresets } from "./errors";
|
|
11
|
-
|
|
12
|
-
test("when the custom function returns expected value", async () => {
|
|
13
|
-
const config = {
|
|
14
|
-
functions: {
|
|
15
|
-
createPost: async (ctx, inputs) => {
|
|
16
|
-
new Permissions().allow();
|
|
17
|
-
|
|
18
|
-
return {
|
|
19
|
-
title: "a post",
|
|
20
|
-
id: "abcde",
|
|
21
|
-
};
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
actionTypes: {
|
|
25
|
-
createPost: PROTO_ACTION_TYPES.CREATE,
|
|
26
|
-
},
|
|
27
|
-
createContextAPI: () => {
|
|
28
|
-
return {
|
|
29
|
-
response: {
|
|
30
|
-
headers: new Headers(),
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const rpcReq = createJSONRPCRequest("123", "createPost", { title: "a post" });
|
|
37
|
-
|
|
38
|
-
expect(await handleRequest(rpcReq, config)).toEqual({
|
|
39
|
-
id: "123",
|
|
40
|
-
jsonrpc: "2.0",
|
|
41
|
-
meta: {
|
|
42
|
-
headers: {},
|
|
43
|
-
},
|
|
44
|
-
result: {
|
|
45
|
-
title: "a post",
|
|
46
|
-
id: "abcde",
|
|
47
|
-
},
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
test("when there is no matching function for the path", async () => {
|
|
52
|
-
const config = {
|
|
53
|
-
functions: {
|
|
54
|
-
createPost: async (ctx, inputs) => {},
|
|
55
|
-
},
|
|
56
|
-
actionTypes: {
|
|
57
|
-
createPost: PROTO_ACTION_TYPES.CREATE,
|
|
58
|
-
},
|
|
59
|
-
createContextAPI: () => {
|
|
60
|
-
return {
|
|
61
|
-
response: {
|
|
62
|
-
headers: new Headers(),
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
},
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const rpcReq = createJSONRPCRequest("123", "unknown", { title: "a post" });
|
|
69
|
-
|
|
70
|
-
expect(await handleRequest(rpcReq, config)).toEqual({
|
|
71
|
-
id: "123",
|
|
72
|
-
jsonrpc: "2.0",
|
|
73
|
-
error: {
|
|
74
|
-
code: JSONRPCErrorCode.MethodNotFound,
|
|
75
|
-
message: "no corresponding function found for 'unknown'",
|
|
76
|
-
},
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
test("when there is an unexpected error in the custom function", async () => {
|
|
81
|
-
const config = {
|
|
82
|
-
functions: {
|
|
83
|
-
createPost: async (ctx, inputs) => {
|
|
84
|
-
throw new Error("oopsie daisy");
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
actionTypes: {
|
|
88
|
-
createPost: PROTO_ACTION_TYPES.CREATE,
|
|
89
|
-
},
|
|
90
|
-
createContextAPI: () => {
|
|
91
|
-
return {
|
|
92
|
-
response: {
|
|
93
|
-
headers: new Headers(),
|
|
94
|
-
},
|
|
95
|
-
};
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
const rpcReq = createJSONRPCRequest("123", "createPost", { title: "a post" });
|
|
100
|
-
|
|
101
|
-
expect(await handleRequest(rpcReq, config)).toEqual({
|
|
102
|
-
id: "123",
|
|
103
|
-
jsonrpc: "2.0",
|
|
104
|
-
error: {
|
|
105
|
-
code: RuntimeErrors.UnknownError,
|
|
106
|
-
message: "oopsie daisy",
|
|
107
|
-
},
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
test("when a role based permission has already been granted by the main runtime", async () => {
|
|
112
|
-
const config = {
|
|
113
|
-
functions: {
|
|
114
|
-
createPost: async (ctx, inputs, api) => {
|
|
115
|
-
return {
|
|
116
|
-
title: inputs.title,
|
|
117
|
-
};
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
actionTypes: {
|
|
121
|
-
createPost: PROTO_ACTION_TYPES.CREATE,
|
|
122
|
-
},
|
|
123
|
-
createModelAPI: () => {},
|
|
124
|
-
createContextAPI: () => {
|
|
125
|
-
return {
|
|
126
|
-
response: {
|
|
127
|
-
headers: new Headers(),
|
|
128
|
-
},
|
|
129
|
-
};
|
|
130
|
-
},
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
let rpcReq = createJSONRPCRequest("123", "createPost", { title: "a post" });
|
|
134
|
-
|
|
135
|
-
Object.assign(rpcReq, {
|
|
136
|
-
...rpcReq,
|
|
137
|
-
meta: { permissionState: { status: "granted", reason: "role" } },
|
|
138
|
-
});
|
|
139
|
-
expect(await handleRequest(rpcReq, config)).toEqual({
|
|
140
|
-
id: "123",
|
|
141
|
-
jsonrpc: "2.0",
|
|
142
|
-
result: {
|
|
143
|
-
title: "a post",
|
|
144
|
-
},
|
|
145
|
-
meta: {
|
|
146
|
-
headers: {},
|
|
147
|
-
},
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
test("when there is an unexpected object thrown in the custom function", async () => {
|
|
152
|
-
const config = {
|
|
153
|
-
functions: {
|
|
154
|
-
createPost: async (ctx, inputs) => {
|
|
155
|
-
throw { err: "oopsie daisy" };
|
|
156
|
-
},
|
|
157
|
-
},
|
|
158
|
-
actionTypes: {
|
|
159
|
-
createPost: PROTO_ACTION_TYPES.CREATE,
|
|
160
|
-
},
|
|
161
|
-
createContextAPI: () => {
|
|
162
|
-
return {
|
|
163
|
-
response: {
|
|
164
|
-
headers: new Headers(),
|
|
165
|
-
},
|
|
166
|
-
};
|
|
167
|
-
},
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
const rpcReq = createJSONRPCRequest("123", "createPost", { title: "a post" });
|
|
171
|
-
|
|
172
|
-
expect(await handleRequest(rpcReq, config)).toEqual({
|
|
173
|
-
id: "123",
|
|
174
|
-
jsonrpc: "2.0",
|
|
175
|
-
error: {
|
|
176
|
-
code: RuntimeErrors.UnknownError,
|
|
177
|
-
message: '{"err":"oopsie daisy"}',
|
|
178
|
-
},
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
test("when a NotFound error preset is thrown in the custom function", async () => {
|
|
183
|
-
const config = {
|
|
184
|
-
functions: {
|
|
185
|
-
createPost: async (ctx, inputs) => {
|
|
186
|
-
throw new ErrorPresets.NotFound("not here");
|
|
187
|
-
},
|
|
188
|
-
},
|
|
189
|
-
actionTypes: {
|
|
190
|
-
createPost: PROTO_ACTION_TYPES.CREATE,
|
|
191
|
-
},
|
|
192
|
-
createContextAPI: () => {
|
|
193
|
-
return {
|
|
194
|
-
response: {
|
|
195
|
-
headers: new Headers(),
|
|
196
|
-
},
|
|
197
|
-
};
|
|
198
|
-
},
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
const rpcReq = createJSONRPCRequest("123", "createPost", { title: "a post" });
|
|
202
|
-
|
|
203
|
-
expect(await handleRequest(rpcReq, config)).toEqual({
|
|
204
|
-
id: "123",
|
|
205
|
-
jsonrpc: "2.0",
|
|
206
|
-
error: {
|
|
207
|
-
code: RuntimeErrors.RecordNotFoundError,
|
|
208
|
-
message: "not here",
|
|
209
|
-
},
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
test("when a NotFound error preset is returned in the custom function", async () => {
|
|
214
|
-
const config = {
|
|
215
|
-
functions: {
|
|
216
|
-
createPost: async (ctx, inputs) => {
|
|
217
|
-
new Permissions().allow();
|
|
218
|
-
return new ErrorPresets.NotFound("not here");
|
|
219
|
-
},
|
|
220
|
-
},
|
|
221
|
-
actionTypes: {
|
|
222
|
-
createPost: PROTO_ACTION_TYPES.CREATE,
|
|
223
|
-
},
|
|
224
|
-
createContextAPI: () => {
|
|
225
|
-
return {
|
|
226
|
-
response: {
|
|
227
|
-
headers: new Headers(),
|
|
228
|
-
},
|
|
229
|
-
};
|
|
230
|
-
},
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
const rpcReq = createJSONRPCRequest("123", "createPost", { title: "a post" });
|
|
234
|
-
|
|
235
|
-
expect(await handleRequest(rpcReq, config)).toEqual({
|
|
236
|
-
id: "123",
|
|
237
|
-
jsonrpc: "2.0",
|
|
238
|
-
error: {
|
|
239
|
-
code: RuntimeErrors.RecordNotFoundError,
|
|
240
|
-
message: "not here",
|
|
241
|
-
},
|
|
242
|
-
});
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
test("when a BadRequest error preset is thrown in the custom function", async () => {
|
|
246
|
-
const config = {
|
|
247
|
-
functions: {
|
|
248
|
-
createPost: async (ctx, inputs) => {
|
|
249
|
-
throw new ErrorPresets.BadRequest("invalid inputs");
|
|
250
|
-
},
|
|
251
|
-
},
|
|
252
|
-
actionTypes: {
|
|
253
|
-
createPost: PROTO_ACTION_TYPES.CREATE,
|
|
254
|
-
},
|
|
255
|
-
createContextAPI: () => {
|
|
256
|
-
return {
|
|
257
|
-
response: {
|
|
258
|
-
headers: new Headers(),
|
|
259
|
-
},
|
|
260
|
-
};
|
|
261
|
-
},
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
const rpcReq = createJSONRPCRequest("123", "createPost", { title: "a post" });
|
|
265
|
-
|
|
266
|
-
expect(await handleRequest(rpcReq, config)).toEqual({
|
|
267
|
-
id: "123",
|
|
268
|
-
jsonrpc: "2.0",
|
|
269
|
-
error: {
|
|
270
|
-
code: RuntimeErrors.BadRequestError,
|
|
271
|
-
message: "invalid inputs",
|
|
272
|
-
},
|
|
273
|
-
});
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
// The following tests assert on the various
|
|
277
|
-
// jsonrpc responses that *should* happen when a user
|
|
278
|
-
// writes a custom function that inadvertently causes a pg constraint error to occur inside of our ModelAPI class instance.
|
|
279
|
-
describe("ModelAPI error handling", () => {
|
|
280
|
-
let functionConfig;
|
|
281
|
-
let db;
|
|
282
|
-
|
|
283
|
-
beforeEach(async () => {
|
|
284
|
-
db = useDatabase();
|
|
285
|
-
|
|
286
|
-
await sql`
|
|
287
|
-
DROP TABLE IF EXISTS post;
|
|
288
|
-
DROP TABLE IF EXISTS author;
|
|
289
|
-
|
|
290
|
-
CREATE TABLE author(
|
|
291
|
-
"id" text PRIMARY KEY,
|
|
292
|
-
"name" text NOT NULL
|
|
293
|
-
);
|
|
294
|
-
|
|
295
|
-
CREATE TABLE post(
|
|
296
|
-
"id" text PRIMARY KEY,
|
|
297
|
-
"title" text NOT NULL UNIQUE,
|
|
298
|
-
"author_id" text NOT NULL REFERENCES author(id)
|
|
299
|
-
);
|
|
300
|
-
`.execute(db);
|
|
301
|
-
|
|
302
|
-
await sql`
|
|
303
|
-
INSERT INTO author (id, name) VALUES ('adam', 'adam bull')
|
|
304
|
-
`.execute(db);
|
|
305
|
-
|
|
306
|
-
const models = {
|
|
307
|
-
post: new ModelAPI("post", undefined, {
|
|
308
|
-
post: {
|
|
309
|
-
author: {
|
|
310
|
-
relationshipType: "belongsTo",
|
|
311
|
-
foreignKey: "author_id",
|
|
312
|
-
referencesTable: "person",
|
|
313
|
-
},
|
|
314
|
-
},
|
|
315
|
-
}),
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
functionConfig = {
|
|
319
|
-
permissionFns: {},
|
|
320
|
-
actionTypes: {
|
|
321
|
-
createPost: PROTO_ACTION_TYPES.CREATE,
|
|
322
|
-
deletePost: PROTO_ACTION_TYPES.DELETE,
|
|
323
|
-
},
|
|
324
|
-
functions: {
|
|
325
|
-
createPost: async (ctx, inputs) => {
|
|
326
|
-
new Permissions().allow();
|
|
327
|
-
|
|
328
|
-
const post = await models.post.create({
|
|
329
|
-
id: KSUID.randomSync().string,
|
|
330
|
-
...inputs,
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
return post;
|
|
334
|
-
},
|
|
335
|
-
deletePost: async (ctx, inputs) => {
|
|
336
|
-
new Permissions().allow();
|
|
337
|
-
|
|
338
|
-
const deleted = await models.post.delete(inputs);
|
|
339
|
-
|
|
340
|
-
return deleted;
|
|
341
|
-
},
|
|
342
|
-
},
|
|
343
|
-
createContextAPI: () => {
|
|
344
|
-
return {
|
|
345
|
-
response: {
|
|
346
|
-
headers: new Headers(),
|
|
347
|
-
},
|
|
348
|
-
};
|
|
349
|
-
},
|
|
350
|
-
};
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
test("when kysely returns a no result error", async () => {
|
|
354
|
-
// a kysely NoResultError is thrown when attempting to delete/update a non existent record.
|
|
355
|
-
const rpcReq = createJSONRPCRequest("123", "deletePost", {
|
|
356
|
-
id: "non-existent-id",
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
expect(await handleRequest(rpcReq, functionConfig)).toEqual({
|
|
360
|
-
id: "123",
|
|
361
|
-
jsonrpc: "2.0",
|
|
362
|
-
error: {
|
|
363
|
-
code: RuntimeErrors.RecordNotFoundError,
|
|
364
|
-
message: "",
|
|
365
|
-
},
|
|
366
|
-
});
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
test("when there is a not null constraint error", async () => {
|
|
370
|
-
const rpcReq = createJSONRPCRequest("123", "createPost", { title: null });
|
|
371
|
-
|
|
372
|
-
expect(await handleRequest(rpcReq, functionConfig)).toEqual({
|
|
373
|
-
id: "123",
|
|
374
|
-
jsonrpc: "2.0",
|
|
375
|
-
error: {
|
|
376
|
-
code: RuntimeErrors.NotNullConstraintError,
|
|
377
|
-
message:
|
|
378
|
-
'null value in column "title" of relation "post" violates not-null constraint',
|
|
379
|
-
data: {
|
|
380
|
-
code: "23502",
|
|
381
|
-
column: "title",
|
|
382
|
-
detail: expect.stringContaining("Failing row contains"),
|
|
383
|
-
table: "post",
|
|
384
|
-
value: undefined,
|
|
385
|
-
},
|
|
386
|
-
},
|
|
387
|
-
});
|
|
388
|
-
});
|
|
389
|
-
test("when there is a uniqueness constraint error", async () => {
|
|
390
|
-
await sql`
|
|
391
|
-
INSERT INTO post (id, title, author_id) values(${
|
|
392
|
-
KSUID.randomSync().string
|
|
393
|
-
}, 'hello', 'adam')
|
|
394
|
-
`.execute(db);
|
|
395
|
-
|
|
396
|
-
const rpcReq = createJSONRPCRequest("123", "createPost", {
|
|
397
|
-
title: "hello",
|
|
398
|
-
author_id: "something",
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
expect(await handleRequest(rpcReq, functionConfig)).toEqual({
|
|
402
|
-
id: "123",
|
|
403
|
-
jsonrpc: "2.0",
|
|
404
|
-
error: {
|
|
405
|
-
code: RuntimeErrors.UniqueConstraintError,
|
|
406
|
-
message:
|
|
407
|
-
'duplicate key value violates unique constraint "post_title_key"',
|
|
408
|
-
data: {
|
|
409
|
-
code: "23505",
|
|
410
|
-
column: "title",
|
|
411
|
-
detail: "Key (title)=(hello) already exists.",
|
|
412
|
-
table: "post",
|
|
413
|
-
value: "hello",
|
|
414
|
-
},
|
|
415
|
-
},
|
|
416
|
-
});
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
test("when there is a null value in a foreign key column", async () => {
|
|
420
|
-
const rpcReq = createJSONRPCRequest("123", "createPost", { title: "123" });
|
|
421
|
-
|
|
422
|
-
expect(await handleRequest(rpcReq, functionConfig)).toEqual({
|
|
423
|
-
id: "123",
|
|
424
|
-
jsonrpc: "2.0",
|
|
425
|
-
error: {
|
|
426
|
-
code: RuntimeErrors.NotNullConstraintError,
|
|
427
|
-
message:
|
|
428
|
-
'null value in column "author_id" of relation "post" violates not-null constraint',
|
|
429
|
-
data: {
|
|
430
|
-
code: "23502",
|
|
431
|
-
column: "author_id",
|
|
432
|
-
detail: expect.stringContaining("Failing row contains"),
|
|
433
|
-
table: "post",
|
|
434
|
-
value: undefined,
|
|
435
|
-
},
|
|
436
|
-
},
|
|
437
|
-
});
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
test("when there is a foreign key constraint violation", async () => {
|
|
441
|
-
const rpcReq2 = createJSONRPCRequest("123", "createPost", {
|
|
442
|
-
title: "123",
|
|
443
|
-
author_id: "fake",
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
expect(await handleRequest(rpcReq2, functionConfig)).toEqual({
|
|
447
|
-
id: "123",
|
|
448
|
-
jsonrpc: "2.0",
|
|
449
|
-
error: {
|
|
450
|
-
code: RuntimeErrors.ForeignKeyConstraintError,
|
|
451
|
-
message:
|
|
452
|
-
'insert or update on table "post" violates foreign key constraint "post_author_id_fkey"',
|
|
453
|
-
data: {
|
|
454
|
-
code: "23503",
|
|
455
|
-
column: "author_id",
|
|
456
|
-
detail: 'Key (author_id)=(fake) is not present in table "author".',
|
|
457
|
-
table: "post",
|
|
458
|
-
value: "fake",
|
|
459
|
-
},
|
|
460
|
-
},
|
|
461
|
-
});
|
|
462
|
-
});
|
|
463
|
-
});
|
package/src/handleRoute.js
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
createJSONRPCErrorResponse,
|
|
3
|
-
createJSONRPCSuccessResponse,
|
|
4
|
-
JSONRPCErrorCode,
|
|
5
|
-
} = require("json-rpc-2.0");
|
|
6
|
-
const { createDatabaseClient, withDatabase } = require("./database");
|
|
7
|
-
const { withAuditContext } = require("./auditing");
|
|
8
|
-
const { errorToJSONRPCResponse, RuntimeErrors } = require("./errors");
|
|
9
|
-
const opentelemetry = require("@opentelemetry/api");
|
|
10
|
-
const { withSpan } = require("./tracing");
|
|
11
|
-
|
|
12
|
-
async function handleRoute(request, config) {
|
|
13
|
-
// Try to extract trace context from caller
|
|
14
|
-
const activeContext = opentelemetry.propagation.extract(
|
|
15
|
-
opentelemetry.context.active(),
|
|
16
|
-
request.meta?.tracing
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
// Run the whole request with the extracted context
|
|
20
|
-
return opentelemetry.context.with(activeContext, () => {
|
|
21
|
-
// Wrapping span for the whole request
|
|
22
|
-
return withSpan(request.method, async (span) => {
|
|
23
|
-
let db = null;
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
const { createContextAPI, functions } = config;
|
|
27
|
-
|
|
28
|
-
if (!(request.method in functions)) {
|
|
29
|
-
const message = `no route function found for '${request.method}'`;
|
|
30
|
-
span.setStatus({
|
|
31
|
-
code: opentelemetry.SpanStatusCode.ERROR,
|
|
32
|
-
message: message,
|
|
33
|
-
});
|
|
34
|
-
return createJSONRPCErrorResponse(
|
|
35
|
-
request.id,
|
|
36
|
-
JSONRPCErrorCode.MethodNotFound,
|
|
37
|
-
message
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// For route functions context doesn't need request headers or the response object as this is handled by
|
|
42
|
-
// params and the function response respectively
|
|
43
|
-
const {
|
|
44
|
-
headers,
|
|
45
|
-
response: __,
|
|
46
|
-
...ctx
|
|
47
|
-
} = createContextAPI({
|
|
48
|
-
responseHeaders: new Headers(),
|
|
49
|
-
meta: request.meta,
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// Add request headers to params
|
|
53
|
-
request.params.headers = headers;
|
|
54
|
-
|
|
55
|
-
db = createDatabaseClient({
|
|
56
|
-
connString: request.meta?.secrets?.KEEL_DB_CONN,
|
|
57
|
-
});
|
|
58
|
-
const routeHandler = functions[request.method];
|
|
59
|
-
|
|
60
|
-
const result = await withDatabase(db, false, () => {
|
|
61
|
-
return withAuditContext(request, () => {
|
|
62
|
-
return routeHandler(request.params, ctx);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
if (result instanceof Error) {
|
|
67
|
-
span.recordException(result);
|
|
68
|
-
span.setStatus({
|
|
69
|
-
code: opentelemetry.SpanStatusCode.ERROR,
|
|
70
|
-
message: result.message,
|
|
71
|
-
});
|
|
72
|
-
return errorToJSONRPCResponse(request, result);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const response = createJSONRPCSuccessResponse(request.id, result);
|
|
76
|
-
|
|
77
|
-
return response;
|
|
78
|
-
} catch (e) {
|
|
79
|
-
if (e instanceof Error) {
|
|
80
|
-
span.recordException(e);
|
|
81
|
-
span.setStatus({
|
|
82
|
-
code: opentelemetry.SpanStatusCode.ERROR,
|
|
83
|
-
message: e.message,
|
|
84
|
-
});
|
|
85
|
-
return errorToJSONRPCResponse(request, e);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const message = JSON.stringify(e);
|
|
89
|
-
|
|
90
|
-
span.setStatus({
|
|
91
|
-
code: opentelemetry.SpanStatusCode.ERROR,
|
|
92
|
-
message: message,
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
return createJSONRPCErrorResponse(
|
|
96
|
-
request.id,
|
|
97
|
-
RuntimeErrors.UnknownError,
|
|
98
|
-
message
|
|
99
|
-
);
|
|
100
|
-
} finally {
|
|
101
|
-
if (db) {
|
|
102
|
-
await db.destroy();
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
module.exports = {
|
|
110
|
-
handleRoute,
|
|
111
|
-
RuntimeErrors,
|
|
112
|
-
};
|
package/src/handleSubscriber.js
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
createJSONRPCErrorResponse,
|
|
3
|
-
createJSONRPCSuccessResponse,
|
|
4
|
-
JSONRPCErrorCode,
|
|
5
|
-
} = require("json-rpc-2.0");
|
|
6
|
-
const { createDatabaseClient } = require("./database");
|
|
7
|
-
const { errorToJSONRPCResponse, RuntimeErrors } = require("./errors");
|
|
8
|
-
const opentelemetry = require("@opentelemetry/api");
|
|
9
|
-
const { withSpan } = require("./tracing");
|
|
10
|
-
const { PROTO_ACTION_TYPES } = require("./consts");
|
|
11
|
-
const { tryExecuteSubscriber } = require("./tryExecuteSubscriber");
|
|
12
|
-
const { parseInputs } = require("./parsing");
|
|
13
|
-
|
|
14
|
-
// Generic handler function that is agnostic to runtime environment (local or lambda)
|
|
15
|
-
// to execute a subscriber function based on the contents of a jsonrpc-2.0 payload object.
|
|
16
|
-
// To read more about jsonrpc request and response shapes, please read https://www.jsonrpc.org/specification
|
|
17
|
-
async function handleSubscriber(request, config) {
|
|
18
|
-
// Try to extract trace context from caller
|
|
19
|
-
const activeContext = opentelemetry.propagation.extract(
|
|
20
|
-
opentelemetry.context.active(),
|
|
21
|
-
request.meta?.tracing
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
// Run the whole request with the extracted context
|
|
25
|
-
return opentelemetry.context.with(activeContext, () => {
|
|
26
|
-
// Wrapping span for the whole request
|
|
27
|
-
return withSpan(request.method, async (span) => {
|
|
28
|
-
let db = null;
|
|
29
|
-
|
|
30
|
-
try {
|
|
31
|
-
const { createSubscriberContextAPI, subscribers } = config;
|
|
32
|
-
|
|
33
|
-
if (!(request.method in subscribers)) {
|
|
34
|
-
const message = `no corresponding subscriber found for '${request.method}'`;
|
|
35
|
-
span.setStatus({
|
|
36
|
-
code: opentelemetry.SpanStatusCode.ERROR,
|
|
37
|
-
message: message,
|
|
38
|
-
});
|
|
39
|
-
return createJSONRPCErrorResponse(
|
|
40
|
-
request.id,
|
|
41
|
-
JSONRPCErrorCode.MethodNotFound,
|
|
42
|
-
message
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// The ctx argument passed into the subscriber function.
|
|
47
|
-
const ctx = createSubscriberContextAPI({
|
|
48
|
-
meta: request.meta,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
db = createDatabaseClient({
|
|
52
|
-
connString: request.meta?.secrets?.KEEL_DB_CONN,
|
|
53
|
-
});
|
|
54
|
-
const subscriberFunction = subscribers[request.method];
|
|
55
|
-
const actionType = PROTO_ACTION_TYPES.SUBSCRIBER;
|
|
56
|
-
|
|
57
|
-
const functionConfig = subscriberFunction?.config ?? {};
|
|
58
|
-
|
|
59
|
-
await tryExecuteSubscriber(
|
|
60
|
-
{ request, db, actionType, functionConfig },
|
|
61
|
-
async () => {
|
|
62
|
-
// parse request params to convert objects into rich field types (e.g. InlineFile)
|
|
63
|
-
const inputs = parseInputs(request.params);
|
|
64
|
-
|
|
65
|
-
// Return the subscriber function to the containing tryExecuteSubscriber block
|
|
66
|
-
return subscriberFunction(ctx, inputs);
|
|
67
|
-
}
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
return createJSONRPCSuccessResponse(request.id, null);
|
|
71
|
-
} catch (e) {
|
|
72
|
-
if (e instanceof Error) {
|
|
73
|
-
span.recordException(e);
|
|
74
|
-
span.setStatus({
|
|
75
|
-
code: opentelemetry.SpanStatusCode.ERROR,
|
|
76
|
-
message: e.message,
|
|
77
|
-
});
|
|
78
|
-
return errorToJSONRPCResponse(request, e);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const message = JSON.stringify(e);
|
|
82
|
-
|
|
83
|
-
span.setStatus({
|
|
84
|
-
code: opentelemetry.SpanStatusCode.ERROR,
|
|
85
|
-
message: message,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
return createJSONRPCErrorResponse(
|
|
89
|
-
request.id,
|
|
90
|
-
RuntimeErrors.UnknownError,
|
|
91
|
-
message
|
|
92
|
-
);
|
|
93
|
-
} finally {
|
|
94
|
-
if (db) {
|
|
95
|
-
await db.destroy();
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
module.exports = {
|
|
103
|
-
handleSubscriber,
|
|
104
|
-
RuntimeErrors,
|
|
105
|
-
};
|