@teamkeel/functions-runtime 0.365.16-12 → 0.365.16-goreleaser-updates13
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/package.json +2 -3
- package/src/ModelAPI.js +27 -68
- package/src/handleSubscriber.js +1 -1
- package/src/tryExecuteFunction.js +2 -6
- package/src/tryExecuteJob.js +2 -5
- package/src/tryExecuteSubscriber.js +2 -5
- package/src/auditing.js +0 -35
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teamkeel/functions-runtime",
|
|
3
|
-
"version": "0.365.16-
|
|
3
|
+
"version": "0.365.16-goreleaser-updates13",
|
|
4
4
|
"description": "Internal package used by @teamkeel/sdk",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
"json-rpc-2.0": "^1.4.1",
|
|
29
29
|
"ksuid": "^3.0.0",
|
|
30
30
|
"kysely": "^0.23.4",
|
|
31
|
-
"pg": "^8.8.0"
|
|
32
|
-
"traceparent": "^1.0.0"
|
|
31
|
+
"pg": "^8.8.0"
|
|
33
32
|
}
|
|
34
33
|
}
|
package/src/ModelAPI.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
const { useDatabase } = require("./database");
|
|
2
|
-
const { getAuditContext } = require("./auditing");
|
|
3
2
|
const { QueryBuilder } = require("./QueryBuilder");
|
|
4
3
|
const { QueryContext } = require("./QueryContext");
|
|
5
4
|
const { applyWhereConditions } = require("./applyWhereConditions");
|
|
6
5
|
const { applyJoins } = require("./applyJoins");
|
|
7
|
-
const { sql } = require("kysely");
|
|
8
|
-
|
|
9
6
|
const {
|
|
10
7
|
applyLimit,
|
|
11
8
|
applyOffset,
|
|
@@ -50,52 +47,12 @@ class ModelAPI {
|
|
|
50
47
|
this._modelName = upperCamelCase(this._tableName);
|
|
51
48
|
}
|
|
52
49
|
|
|
53
|
-
// execute sets the audit context in the database and then runs individual
|
|
54
|
-
// database statements within a transaction if one hasn't been opened, which
|
|
55
|
-
// is necessary because the audit parameters will only be available within transactions.
|
|
56
|
-
async #execute(fn) {
|
|
57
|
-
const db = useDatabase();
|
|
58
|
-
|
|
59
|
-
try {
|
|
60
|
-
if (db.isTransaction) {
|
|
61
|
-
await this.#setAuditParameters(db);
|
|
62
|
-
return await fn(db);
|
|
63
|
-
} else {
|
|
64
|
-
return await db.transaction().execute(async (transaction) => {
|
|
65
|
-
await this.#setAuditParameters(transaction);
|
|
66
|
-
return fn(transaction);
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
} catch (e) {
|
|
70
|
-
throw new DatabaseError(e);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// setAuditParameters sets audit context data to configuration parameters
|
|
75
|
-
// in the database so that they can be read by the triggered auditing function.
|
|
76
|
-
async #setAuditParameters(transaction) {
|
|
77
|
-
const audit = getAuditContext();
|
|
78
|
-
const statements = [];
|
|
79
|
-
|
|
80
|
-
if (audit.identityId) {
|
|
81
|
-
statements.push(`CALL set_identity_id('${audit.identityId}');`);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (audit.traceId) {
|
|
85
|
-
statements.push(`CALL set_trace_id('${audit.traceId}');`);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (statements.length > 0) {
|
|
89
|
-
const stmt = statements.join("");
|
|
90
|
-
await sql.raw(stmt).execute(transaction);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
50
|
async create(values) {
|
|
95
51
|
const name = tracing.spanNameForModelAPI(this._modelName, "create");
|
|
52
|
+
const db = useDatabase();
|
|
96
53
|
|
|
97
54
|
return tracing.withSpan(name, async (span) => {
|
|
98
|
-
|
|
55
|
+
try {
|
|
99
56
|
const query = db
|
|
100
57
|
.insertInto(this._tableName)
|
|
101
58
|
.values(
|
|
@@ -107,8 +64,11 @@ class ModelAPI {
|
|
|
107
64
|
|
|
108
65
|
span.setAttribute("sql", query.compile().sql);
|
|
109
66
|
const row = await query.executeTakeFirstOrThrow();
|
|
67
|
+
|
|
110
68
|
return camelCaseObject(row);
|
|
111
|
-
})
|
|
69
|
+
} catch (e) {
|
|
70
|
+
throw new DatabaseError(e);
|
|
71
|
+
}
|
|
112
72
|
});
|
|
113
73
|
}
|
|
114
74
|
|
|
@@ -195,49 +155,48 @@ class ModelAPI {
|
|
|
195
155
|
|
|
196
156
|
async update(where, values) {
|
|
197
157
|
const name = tracing.spanNameForModelAPI(this._modelName, "update");
|
|
158
|
+
const db = useDatabase();
|
|
198
159
|
|
|
199
160
|
return tracing.withSpan(name, async (span) => {
|
|
200
|
-
|
|
201
|
-
let builder = db.updateTable(this._tableName).returningAll();
|
|
161
|
+
let builder = db.updateTable(this._tableName).returningAll();
|
|
202
162
|
|
|
203
|
-
|
|
163
|
+
builder = builder.set(snakeCaseObject(values));
|
|
204
164
|
|
|
205
|
-
|
|
206
|
-
[this._tableName],
|
|
207
|
-
this._tableConfigMap
|
|
208
|
-
);
|
|
165
|
+
const context = new QueryContext([this._tableName], this._tableConfigMap);
|
|
209
166
|
|
|
210
|
-
|
|
211
|
-
|
|
167
|
+
// TODO: support joins for update
|
|
168
|
+
builder = applyWhereConditions(context, builder, where);
|
|
212
169
|
|
|
213
|
-
|
|
170
|
+
span.setAttribute("sql", builder.compile().sql);
|
|
214
171
|
|
|
172
|
+
try {
|
|
215
173
|
const row = await builder.executeTakeFirstOrThrow();
|
|
216
174
|
return camelCaseObject(row);
|
|
217
|
-
})
|
|
175
|
+
} catch (e) {
|
|
176
|
+
throw new DatabaseError(e);
|
|
177
|
+
}
|
|
218
178
|
});
|
|
219
179
|
}
|
|
220
180
|
|
|
221
181
|
async delete(where) {
|
|
222
182
|
const name = tracing.spanNameForModelAPI(this._modelName, "delete");
|
|
183
|
+
const db = useDatabase();
|
|
223
184
|
|
|
224
185
|
return tracing.withSpan(name, async (span) => {
|
|
225
|
-
|
|
226
|
-
let builder = db.deleteFrom(this._tableName).returning(["id"]);
|
|
227
|
-
|
|
228
|
-
const context = new QueryContext(
|
|
229
|
-
[this._tableName],
|
|
230
|
-
this._tableConfigMap
|
|
231
|
-
);
|
|
186
|
+
let builder = db.deleteFrom(this._tableName).returning(["id"]);
|
|
232
187
|
|
|
233
|
-
|
|
234
|
-
builder = applyWhereConditions(context, builder, where);
|
|
188
|
+
const context = new QueryContext([this._tableName], this._tableConfigMap);
|
|
235
189
|
|
|
236
|
-
|
|
190
|
+
// TODO: support joins for delete
|
|
191
|
+
builder = applyWhereConditions(context, builder, where);
|
|
237
192
|
|
|
193
|
+
span.setAttribute("sql", builder.compile().sql);
|
|
194
|
+
try {
|
|
238
195
|
const row = await builder.executeTakeFirstOrThrow();
|
|
239
196
|
return row.id;
|
|
240
|
-
})
|
|
197
|
+
} catch (e) {
|
|
198
|
+
throw new DatabaseError(e);
|
|
199
|
+
}
|
|
241
200
|
});
|
|
242
201
|
}
|
|
243
202
|
|
package/src/handleSubscriber.js
CHANGED
|
@@ -49,7 +49,7 @@ async function handleSubscriber(request, config) {
|
|
|
49
49
|
const subscriberFunction = subscribers[request.method];
|
|
50
50
|
const actionType = PROTO_ACTION_TYPES.SUBSCRIBER;
|
|
51
51
|
|
|
52
|
-
await tryExecuteSubscriber({
|
|
52
|
+
await tryExecuteSubscriber({ db, actionType }, async () => {
|
|
53
53
|
// Return the subscriber function to the containing tryExecuteSubscriber block
|
|
54
54
|
return subscriberFunction(ctx, request.params);
|
|
55
55
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const { withDatabase } = require("./database");
|
|
2
|
-
const { withAuditContext } = require("./auditing");
|
|
3
2
|
const {
|
|
4
3
|
withPermissions,
|
|
5
4
|
PERMISSION_STATE,
|
|
@@ -11,15 +10,12 @@ const { PROTO_ACTION_TYPES } = require("./consts");
|
|
|
11
10
|
// tryExecuteFunction will create a new database transaction around a function call
|
|
12
11
|
// and handle any permissions checks. If a permission check fails, then an Error will be thrown and the catch block will be hit.
|
|
13
12
|
function tryExecuteFunction(
|
|
14
|
-
{
|
|
13
|
+
{ db, permitted, permissionFns, actionType, request, ctx },
|
|
15
14
|
cb
|
|
16
15
|
) {
|
|
17
16
|
return withPermissions(permitted, async ({ getPermissionState }) => {
|
|
18
17
|
return withDatabase(db, actionType, async ({ transaction }) => {
|
|
19
|
-
const fnResult = await
|
|
20
|
-
return cb();
|
|
21
|
-
});
|
|
22
|
-
|
|
18
|
+
const fnResult = await cb();
|
|
23
19
|
// api.permissions maintains an internal state of whether the current function has been *explicitly* permitted/denied by the user in the course of their custom function, or if execution has already been permitted by a role based permission (evaluated in the main runtime).
|
|
24
20
|
// we need to check that the final state is permitted or unpermitted. if it's not, then it means that the user has taken no explicit action to permit/deny
|
|
25
21
|
// and therefore we default to checking the permissions defined in the schema automatically.
|
package/src/tryExecuteJob.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { withDatabase } = require("./database");
|
|
2
|
-
const { withAuditContext } = require("./auditing");
|
|
3
2
|
const { withPermissions, PERMISSION_STATE } = require("./permissions");
|
|
3
|
+
|
|
4
4
|
const { PermissionError } = require("./errors");
|
|
5
5
|
|
|
6
6
|
// tryExecuteJob will create a new database transaction around a function call
|
|
@@ -8,10 +8,7 @@ const { PermissionError } = require("./errors");
|
|
|
8
8
|
function tryExecuteJob({ db, permitted, actionType, request }, cb) {
|
|
9
9
|
return withPermissions(permitted, async ({ getPermissionState }) => {
|
|
10
10
|
return withDatabase(db, actionType, async () => {
|
|
11
|
-
await
|
|
12
|
-
return cb();
|
|
13
|
-
});
|
|
14
|
-
|
|
11
|
+
await cb();
|
|
15
12
|
// api.permissions maintains an internal state of whether the current operation has been *explicitly* permitted/denied by the user in the course of their custom function, or if execution has already been permitted by a role based permission (evaluated in the main runtime).
|
|
16
13
|
// we need to check that the final state is permitted or unpermitted. if it's not, then it means that the user has taken no explicit action to permit/deny
|
|
17
14
|
// and therefore we default to checking the permissions defined in the schema automatically.
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
const { withDatabase } = require("./database");
|
|
2
|
-
const { withAuditContext } = require("./auditing");
|
|
3
2
|
|
|
4
3
|
// tryExecuteSubscriber will create a new database connection and execute the function call.
|
|
5
|
-
function tryExecuteSubscriber({
|
|
4
|
+
function tryExecuteSubscriber({ db, actionType }, cb) {
|
|
6
5
|
return withDatabase(db, actionType, async () => {
|
|
7
|
-
await
|
|
8
|
-
return cb();
|
|
9
|
-
});
|
|
6
|
+
await cb();
|
|
10
7
|
});
|
|
11
8
|
}
|
|
12
9
|
|
package/src/auditing.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
const { AsyncLocalStorage } = require("async_hooks");
|
|
2
|
-
const TraceParent = require("traceparent");
|
|
3
|
-
|
|
4
|
-
const auditContextStorage = new AsyncLocalStorage();
|
|
5
|
-
|
|
6
|
-
// withAuditContext creates the audit context from the runtime request body
|
|
7
|
-
// and sets it to in AsyncLocalStorage so that this data is available to the
|
|
8
|
-
// ModelAPI during the execution of actions, jobs and subscribers.
|
|
9
|
-
async function withAuditContext(request, cb) {
|
|
10
|
-
let audit = {};
|
|
11
|
-
if (request.meta?.identity) {
|
|
12
|
-
audit.identityId = request.meta.identity.id;
|
|
13
|
-
}
|
|
14
|
-
if (request.meta?.tracing?.traceparent) {
|
|
15
|
-
audit.traceId = TraceParent.fromString(
|
|
16
|
-
request.meta.tracing.traceparent
|
|
17
|
-
)?.traceId;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return await auditContextStorage.run(audit, () => {
|
|
21
|
-
return cb();
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// getAuditContext retrieves the audit context from AsyncLocalStorage.
|
|
26
|
-
function getAuditContext() {
|
|
27
|
-
let auditStore = auditContextStorage.getStore();
|
|
28
|
-
return {
|
|
29
|
-
identityId: auditStore?.identityId,
|
|
30
|
-
traceId: auditStore?.traceId,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
module.exports.withAuditContext = withAuditContext;
|
|
35
|
-
module.exports.getAuditContext = getAuditContext;
|