@teamkeel/functions-runtime 0.236.1 → 0.236.3

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.
@@ -0,0 +1,52 @@
1
+ const {
2
+ createJSONRPCErrorResponse,
3
+ createJSONRPCSuccessResponse,
4
+ JSONRPCErrorCode,
5
+ } = require("json-rpc-2.0");
6
+
7
+ // Generic handler function that is agnostic to runtime environment (local or lambda)
8
+ // to execute a custom function based on the contents of a jsonrpc-2.0 payload object.
9
+ // To read more about jsonrpc request and response shapes, please read https://www.jsonrpc.org/specification
10
+ export async function handleRequest(request, config) {
11
+ const { createFunctionAPI, functions } = config;
12
+
13
+ if (!(request.method in functions)) {
14
+ return createJSONRPCErrorResponse(
15
+ request.id,
16
+ JSONRPCErrorCode.MethodNotFound,
17
+ `no corresponding function found for '${request.method}'`
18
+ );
19
+ }
20
+
21
+ try {
22
+ const result = await functions[request.method](
23
+ request.params,
24
+ createFunctionAPI()
25
+ );
26
+
27
+ if (result === undefined) {
28
+ // no result returned from custom function
29
+ return createJSONRPCErrorResponse(
30
+ request.id,
31
+ JSONRPCErrorCode.InternalError,
32
+ `no result returned from function '${request.method}'`
33
+ );
34
+ }
35
+
36
+ return createJSONRPCSuccessResponse(request.id, result);
37
+ } catch (e) {
38
+ let msg = "";
39
+
40
+ if (e instanceof Error) {
41
+ msg = e.message;
42
+ } else {
43
+ msg = JSON.stringify(e);
44
+ }
45
+
46
+ return createJSONRPCErrorResponse(
47
+ request.id,
48
+ JSONRPCErrorCode.InternalError,
49
+ msg
50
+ );
51
+ }
52
+ }
@@ -0,0 +1,112 @@
1
+ import { createJSONRPCRequest, JSONRPCErrorCode } from "json-rpc-2.0";
2
+ import { handleRequest } from "./handleRequest";
3
+ import { test, expect } from "vitest";
4
+
5
+ test("when the custom function returns expected value", async () => {
6
+ const config = {
7
+ functions: {
8
+ createPost: async () => {
9
+ return {
10
+ title: "a post",
11
+ id: "abcde",
12
+ };
13
+ },
14
+ },
15
+ createFunctionAPI: () => {},
16
+ };
17
+
18
+ const rpcReq = createJSONRPCRequest("123", "createPost", { title: "a post" });
19
+
20
+ expect(await handleRequest(rpcReq, config)).toEqual({
21
+ id: "123",
22
+ jsonrpc: "2.0",
23
+ result: {
24
+ title: "a post",
25
+ id: "abcde",
26
+ },
27
+ });
28
+ });
29
+
30
+ test("when the custom function doesnt return a value", async () => {
31
+ const config = {
32
+ functions: {
33
+ createPost: async () => {},
34
+ },
35
+ createFunctionAPI: () => {},
36
+ };
37
+
38
+ const rpcReq = createJSONRPCRequest("123", "createPost", { title: "a post" });
39
+
40
+ expect(await handleRequest(rpcReq, config)).toEqual({
41
+ id: "123",
42
+ jsonrpc: "2.0",
43
+ error: {
44
+ code: JSONRPCErrorCode.InternalError,
45
+ message: "no result returned from function 'createPost'",
46
+ },
47
+ });
48
+ });
49
+
50
+ test("when there is no matching function for the path", async () => {
51
+ const config = {
52
+ functions: {
53
+ createPost: async () => {},
54
+ },
55
+ createFunctionAPI: () => {},
56
+ };
57
+
58
+ const rpcReq = createJSONRPCRequest("123", "unknown", { title: "a post" });
59
+
60
+ expect(await handleRequest(rpcReq, config)).toEqual({
61
+ id: "123",
62
+ jsonrpc: "2.0",
63
+ error: {
64
+ code: JSONRPCErrorCode.MethodNotFound,
65
+ message: "no corresponding function found for 'unknown'",
66
+ },
67
+ });
68
+ });
69
+
70
+ test("when there is an unexpected error in the custom function", async () => {
71
+ const config = {
72
+ functions: {
73
+ createPost: () => {
74
+ throw new Error("oopsie daisy");
75
+ },
76
+ },
77
+ createFunctionAPI: () => {},
78
+ };
79
+
80
+ const rpcReq = createJSONRPCRequest("123", "createPost", { title: "a post" });
81
+
82
+ expect(await handleRequest(rpcReq, config)).toEqual({
83
+ id: "123",
84
+ jsonrpc: "2.0",
85
+ error: {
86
+ code: JSONRPCErrorCode.InternalError,
87
+ message: "oopsie daisy",
88
+ },
89
+ });
90
+ });
91
+
92
+ test("when there is an unexpected object thrown in the custom function", async () => {
93
+ const config = {
94
+ functions: {
95
+ createPost: () => {
96
+ throw { err: "oopsie daisy" };
97
+ },
98
+ },
99
+ createFunctionAPI: () => {},
100
+ };
101
+
102
+ const rpcReq = createJSONRPCRequest("123", "createPost", { title: "a post" });
103
+
104
+ expect(await handleRequest(rpcReq, config)).toEqual({
105
+ id: "123",
106
+ jsonrpc: "2.0",
107
+ error: {
108
+ code: JSONRPCErrorCode.InternalError,
109
+ message: '{"err":"oopsie daisy"}',
110
+ },
111
+ });
112
+ });
package/src/index.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ export type IDWhereCondition = {
2
+ equals?: string;
3
+ oneOf?: string[];
4
+ };
5
+
6
+ export type StringWhereCondition = {
7
+ startsWith?: string;
8
+ endsWith?: string;
9
+ oneOf?: string[];
10
+ contains?: string;
11
+ notEquals?: string;
12
+ equals?: string;
13
+ };
14
+
15
+ export type BooleanWhereCondition = {
16
+ equals?: boolean;
17
+ notEquals?: boolean;
18
+ };
19
+
20
+ export type NumberWhereCondition = {
21
+ greaterThan?: number;
22
+ greaterThanOrEquals?: number;
23
+ lessThan?: number;
24
+ lessThanOrEquals?: number;
25
+ equals?: number;
26
+ notEquals?: number;
27
+ };
28
+
29
+ export type DateWhereCondition = {
30
+ equals?: Date;
31
+ before?: Date;
32
+ onOrBefore?: Date;
33
+ after?: Date;
34
+ onOrAfter?: Date;
35
+ };
package/src/index.js ADDED
@@ -0,0 +1,9 @@
1
+ const { ModelAPI } = require("./ModelAPI");
2
+ const { handleRequest } = require("./handleRequest");
3
+ const { getDatabase } = require("./database");
4
+
5
+ module.exports = {
6
+ ModelAPI,
7
+ handleRequest,
8
+ getDatabase,
9
+ };
package/dist/index.d.ts DELETED
@@ -1,296 +0,0 @@
1
- declare module '@teamkeel/functions-runtime/constraints' {
2
- export type StringConstraint = string | {
3
- startsWith?: string;
4
- endsWith?: string;
5
- oneOf?: string[];
6
- contains?: string;
7
- notEquals?: string;
8
- equals?: string;
9
- };
10
- export type NumberConstraint = number | {
11
- greaterThan?: number;
12
- greaterThanOrEquals?: number;
13
- lessThan?: number;
14
- lessThanOrEquals?: number;
15
- equals?: number;
16
- notEquals?: number;
17
- };
18
- export type BooleanConstraint = boolean | {
19
- equals?: boolean;
20
- notEquals?: boolean;
21
- };
22
- export type DateConstraint = Date | {
23
- equals?: Date;
24
- before?: Date;
25
- onOrBefore?: Date;
26
- after?: Date;
27
- onOrAfter?: Date;
28
- };
29
- export type EnumConstraint = StringConstraint;
30
-
31
- }
32
- declare module '@teamkeel/functions-runtime/customFunctions/index' {
33
- import { Config, CustomFunctionResponsePayload, CustomFunctionRequestPayload } from "@teamkeel/functions-runtime/types";
34
- const handler: ({ method, params, id }: CustomFunctionRequestPayload, config: Config) => Promise<CustomFunctionResponsePayload>;
35
- export default handler;
36
-
37
- }
38
- declare module '@teamkeel/functions-runtime/db/query' {
39
- export type SqlQueryParts = SqlQueryPart[];
40
- export type SqlQueryPart = RawSql | SqlInput;
41
- export type RawSql = {
42
- type: "sql";
43
- value: string;
44
- };
45
- export type SqlInput = {
46
- type: "input";
47
- value: any;
48
- };
49
- export function rawSql(sql: string): SqlQueryPart;
50
- export function sqlIdentifier(identifier: string, identifierField?: string | null): SqlQueryPart;
51
- export function sqlInput(input: any): SqlQueryPart;
52
- export function sqlInputArray(inputs: any[]): SqlQueryPart[];
53
- export function sqlAddSeparator(parts: SqlQueryPart[], separator: SqlQueryPart): SqlQueryPart[];
54
- export function sqlAddSeparatorAndFlatten(parts: SqlQueryPart[][], separator: SqlQueryPart): SqlQueryPart[];
55
-
56
- }
57
- declare module '@teamkeel/functions-runtime/db/resolver' {
58
- import { SqlQueryParts } from "@teamkeel/functions-runtime/db/query";
59
- export interface QueryResolver {
60
- runQuery(query: SqlQueryParts): Promise<QueryResultRow[]>;
61
- runRawQuery(query: string): Promise<QueryResultRow[]>;
62
- }
63
- export interface QueryResultRow {
64
- [column: string]: any;
65
- }
66
- export function queryResolverFromEnv(env: Record<string, string | undefined>): QueryResolver;
67
- export class PgQueryResolver implements QueryResolver {
68
- private readonly pool;
69
- constructor(config: {
70
- connectionString: string;
71
- });
72
- runRawQuery(query: string): Promise<QueryResultRow[]>;
73
- runQuery(query: SqlQueryParts): Promise<QueryResultRow[]>;
74
- private toQuery;
75
- }
76
- export class AwsRdsDataClientQueryResolver implements QueryResolver {
77
- private readonly client;
78
- private readonly dbClusterResourceArn;
79
- private readonly dbCredentialsSecretArn;
80
- private readonly dbName;
81
- constructor(config: {
82
- region: string;
83
- dbClusterResourceArn: string;
84
- dbCredentialsSecretArn: string;
85
- dbName: string;
86
- });
87
- runRawQuery(sql: string): Promise<QueryResultRow[]>;
88
- runQuery(query: SqlQueryParts): Promise<QueryResultRow[]>;
89
- private toQuery;
90
- private toDataApiFormat;
91
- }
92
-
93
- }
94
- declare module '@teamkeel/functions-runtime/fetch/index' {
95
- import { RequestInit } from "node-fetch";
96
- type RequestOpts = Omit<RequestInit, "referrer">;
97
- const _default: (uri: string, opts: RequestOpts) => Promise<import("node-fetch").Response>;
98
- export default _default;
99
-
100
- }
101
- declare module '@teamkeel/functions-runtime/index' {
102
- import Query, { ChainableQuery } from "@teamkeel/functions-runtime/query";
103
- import * as QueryConstraints from "@teamkeel/functions-runtime/constraints";
104
- import Logger, { ConsoleTransport, Level as LogLevel } from "@teamkeel/functions-runtime/logger/index";
105
- import { Identity } from "@teamkeel/functions-runtime/types";
106
- import handleCustomFunction from "@teamkeel/functions-runtime/customFunctions/index";
107
- export * from "@teamkeel/functions-runtime/returnTypes";
108
- export * from "@teamkeel/functions-runtime/db/resolver";
109
- import { queryResolverFromEnv } from "@teamkeel/functions-runtime/db/resolver";
110
- export { Query, ChainableQuery, QueryConstraints, Logger, ConsoleTransport, LogLevel, Identity, queryResolverFromEnv, handleCustomFunction, };
111
-
112
- }
113
- declare module '@teamkeel/functions-runtime/logger/index' {
114
- export enum Level {
115
- Info = "info",
116
- Error = "error",
117
- Debug = "debug",
118
- Warn = "warn",
119
- Success = "success"
120
- }
121
- export interface LoggerOptions {
122
- transport?: Transport;
123
- colorize?: boolean;
124
- timestamps?: boolean;
125
- }
126
- export interface Transport {
127
- log: (msg: Msg, level: Level, options: LoggerOptions) => void;
128
- }
129
- export class ConsoleTransport implements Transport {
130
- log: (msg: Msg, level: Level, options: LoggerOptions) => void;
131
- }
132
- type Msg = any;
133
- export default class Logger {
134
- private readonly options;
135
- constructor(opts?: LoggerOptions);
136
- log: (msg: Msg, level?: Level) => void;
137
- }
138
- export {};
139
-
140
- }
141
- declare module '@teamkeel/functions-runtime/query' {
142
- import { Conditions, ChainedQueryOpts, QueryOpts, Input, OrderClauses } from "@teamkeel/functions-runtime/types";
143
- import * as ReturnTypes from "@teamkeel/functions-runtime/returnTypes";
144
- import { QueryResultRow } from "@teamkeel/functions-runtime/db/resolver";
145
- export class ChainableQuery<T extends IDer> {
146
- private readonly tableName;
147
- private readonly conditions;
148
- private orderClauses;
149
- private readonly queryResolver;
150
- private readonly logger;
151
- constructor({ tableName, queryResolver, conditions, logger, }: ChainedQueryOpts<T>);
152
- orWhere: (conditions: Conditions<T>) => ChainableQuery<T>;
153
- all: () => Promise<ReturnTypes.FunctionListResponse<T>>;
154
- findOne: () => Promise<ReturnTypes.FunctionGetResponse<T>>;
155
- order: (clauses: OrderClauses<T>) => ChainableQuery<T>;
156
- private appendConditions;
157
- private execute;
158
- }
159
- interface IDer {
160
- id: string;
161
- }
162
- export default class Query<T extends IDer> {
163
- private readonly tableName;
164
- private readonly conditions;
165
- private readonly queryResolver;
166
- private readonly logger;
167
- constructor({ tableName, queryResolver, logger }: QueryOpts);
168
- create: (inputs: Partial<T>) => Promise<ReturnTypes.FunctionCreateResponse<T>>;
169
- raw: (sql: string) => Promise<QueryResultRow[]>;
170
- where: (conditions: Conditions<T>) => ChainableQuery<T>;
171
- delete: (id: string) => Promise<ReturnTypes.FunctionDeleteResponse<T>>;
172
- findOne: (conditions: Conditions<T>) => Promise<ReturnTypes.FunctionGetResponse<T>>;
173
- update: (id: string, inputs: Input<T>) => Promise<ReturnTypes.FunctionUpdateResponse<T>>;
174
- all: () => Promise<ReturnTypes.FunctionListResponse<T>>;
175
- private execute;
176
- }
177
- export {};
178
-
179
- }
180
- declare module '@teamkeel/functions-runtime/queryBuilders/index' {
181
- import { Conditions, Constraints, OrderClauses, OrderDirection } from "@teamkeel/functions-runtime/types";
182
- import { SqlQueryParts } from "@teamkeel/functions-runtime/db/query";
183
- export const buildSelectStatement: <T>(tableName: string, conditions: Partial<{ [K in keyof T]: Constraints<T[K]>; }>[], order?: Partial<Record<keyof T, OrderDirection>>, limit?: number) => SqlQueryParts;
184
- export const buildCreateStatement: <T>(tableName: string, inputs: Partial<T>) => SqlQueryParts;
185
- export const buildUpdateStatement: <T>(tableName: string, id: string, inputs: Partial<T>) => SqlQueryParts;
186
- export const buildDeleteStatement: <T>(tableName: string, id: string) => SqlQueryParts;
187
-
188
- }
189
- declare module '@teamkeel/functions-runtime/returnTypes' {
190
- export interface ValidationError {
191
- field: string;
192
- message: string;
193
- code: string;
194
- }
195
- export interface ExecutionError {
196
- message: string;
197
- stack: string;
198
- }
199
- export type FunctionError = ValidationError | ExecutionError;
200
- export interface FunctionCreateResponse<T> {
201
- object?: T;
202
- errors?: FunctionError[];
203
- }
204
- export interface FunctionGetResponse<T> {
205
- object?: T;
206
- errors?: FunctionError[];
207
- }
208
- export interface FunctionDeleteResponse<T> {
209
- success: boolean;
210
- errors?: FunctionError[];
211
- }
212
- export interface FunctionListResponse<T> {
213
- collection: T[];
214
- errors?: FunctionError[];
215
- }
216
- export interface FunctionUpdateResponse<T> {
217
- object?: T;
218
- errors?: FunctionError[];
219
- }
220
- export interface FunctionAuthenticateResponse {
221
- identityId?: string;
222
- identityCreated: boolean;
223
- errors?: FunctionError[];
224
- }
225
-
226
- }
227
- declare module '@teamkeel/functions-runtime/staticAnalysis/analyse' {
228
- export interface AnalyseOptions {
229
- path: string;
230
- }
231
- const _default: (opts: AnalyseOptions) => Promise<import("@structured-types/api").PropTypes>;
232
- export default _default;
233
-
234
- }
235
- declare module '@teamkeel/functions-runtime/staticAnalysis/cli' {
236
- export {};
237
-
238
- }
239
- declare module '@teamkeel/functions-runtime/types' {
240
- import { JSONRPCRequest, JSONRPCResponse } from "json-rpc-2.0";
241
- import { StringConstraint, BooleanConstraint, NumberConstraint, DateConstraint, EnumConstraint } from "@teamkeel/functions-runtime/constraints";
242
- import { Logger } from "@teamkeel/functions-runtime/index";
243
- import Query from "@teamkeel/functions-runtime/query";
244
- import { QueryResolver } from "@teamkeel/functions-runtime/db/resolver";
245
- export interface QueryOpts {
246
- tableName: string;
247
- queryResolver: QueryResolver;
248
- logger: Logger;
249
- }
250
- export interface ChainedQueryOpts<T> extends QueryOpts {
251
- conditions: Conditions<T>[];
252
- }
253
- export type Constraints<T> = T extends String ? StringConstraint : T extends Boolean ? BooleanConstraint : T extends Number ? NumberConstraint : T extends Date ? DateConstraint : EnumConstraint;
254
- export type Input<T> = Record<keyof T, unknown>;
255
- export type Conditions<T> = Partial<{
256
- [K in keyof T]: Constraints<T[K]>;
257
- }>;
258
- export interface BuiltInFields {
259
- id: string;
260
- createdAt: Date;
261
- updatedAt: Date;
262
- }
263
- export type OrderDirection = "ASC" | "DESC";
264
- export type OrderClauses<T> = Partial<Record<keyof T, OrderDirection>>;
265
- export interface Identity {
266
- id: string;
267
- email: string;
268
- }
269
- export type CustomFunctionRequestPayload = JSONRPCRequest;
270
- export type CustomFunctionResponsePayload = JSONRPCResponse;
271
- export type CustomFunction = (inputs: any, api: API) => Promise<any>;
272
- type API = {
273
- [apiName: string]: Query<BuiltInFields>;
274
- };
275
- export type Functions = Record<string, CustomFunction>;
276
- export interface Config {
277
- functions: Functions;
278
- api: API;
279
- }
280
- export {};
281
-
282
- }
283
- declare module '@teamkeel/functions-runtime/util/camelCaser' {
284
- const _default: (input: string) => string;
285
- export default _default;
286
-
287
- }
288
- declare module '@teamkeel/functions-runtime/util/snakeCaser' {
289
- const _default: (input: string) => string;
290
- export default _default;
291
-
292
- }
293
- declare module '@teamkeel/functions-runtime' {
294
- import main = require('@teamkeel/functions-runtime/index');
295
- export = main;
296
- }